1 /**
2 *
3 * Copyright 2004 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.geronimo.security.remoting.jmx;
19
20 import java.io.IOException;
21 import java.net.InetSocketAddress;
22 import java.net.URI;
23 import java.net.URISyntaxException;
24 import javax.management.ObjectName;
25 import org.activeio.AcceptListener;
26 import org.activeio.AsyncChannelServer;
27 import org.activeio.Channel;
28 import org.activeio.Packet;
29 import org.activeio.RequestChannel;
30 import org.activeio.SyncChannel;
31 import org.activeio.SyncChannelServer;
32 import org.activeio.adapter.AsyncChannelToServerRequestChannel;
33 import org.activeio.adapter.AsyncToSyncChannel;
34 import org.activeio.adapter.SyncToAsyncChannel;
35 import org.activeio.adapter.SyncToAsyncChannelServer;
36 import org.activeio.filter.PacketAggregatingAsyncChannel;
37 import org.activeio.net.SocketMetadata;
38 import org.activeio.net.SocketSyncChannelFactory;
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41 import org.apache.geronimo.gbean.GBeanInfo;
42 import org.apache.geronimo.gbean.GBeanInfoBuilder;
43 import org.apache.geronimo.gbean.GBeanLifecycle;
44 import org.apache.geronimo.kernel.ObjectNameUtil;
45 import org.apache.geronimo.management.geronimo.NetworkConnector;
46 import org.apache.geronimo.security.jaas.server.JaasLoginServiceMBean;
47
48
49 /**
50 * A server-side utility that exposes a JaasLoginService to remote clients.
51 * It prevents clients from connecting to arbitrary server-side MBeans through
52 * this listener -- only the JaasLoginService is exposed.
53 *
54 * @version $Rev: 417891 $ $Date: 2006-06-28 15:45:07 -0700 (Wed, 28 Jun 2006) $
55 */
56 public class JaasLoginServiceRemotingServer implements GBeanLifecycle, NetworkConnector {
57
58 public static final ObjectName REQUIRED_OBJECT_NAME = ObjectNameUtil.getObjectName("geronimo.remoting:target=JaasLoginServiceRemotingServer");
59
60 private static final Log log = LogFactory.getLog(JaasLoginServiceRemotingServer.class);
61 private AsyncChannelServer server;
62 private JaasLoginServiceMBean loginService;
63 private String protocol;
64 private String host;
65 private int port;
66
67 public JaasLoginServiceRemotingServer(String protocol, String host, int port, JaasLoginServiceMBean loginService) {
68 this.protocol = protocol;
69 this.host = host;
70 this.port = port;
71 this.loginService = loginService;
72 }
73
74 public String getProtocol() {
75 return protocol;
76 }
77
78 public void setProtocol(String protocol) {
79 this.protocol = protocol;
80 }
81
82 public String getHost() {
83 return host;
84 }
85
86 public void setHost(String host) {
87 this.host = host;
88 }
89
90 public int getPort() {
91 return port;
92 }
93
94 public void setPort(int port) {
95 this.port = port;
96 }
97
98 public URI getClientConnectURI() {
99 return server.getConnectURI();
100 }
101
102 public InetSocketAddress getListenAddress() {
103 if (server != null) {
104 URI uri = server.getBindURI();
105 return new InetSocketAddress(uri.getHost(), uri.getPort());
106 } else {
107 return new InetSocketAddress(host, port);
108 }
109 }
110
111 public void doStart() throws Exception {
112 final ReflexiveInterceptor loginServiceInterceptor = new ReflexiveInterceptor(loginService);
113
114 server = createAsyncChannelServer();
115 server.setAcceptListener(new AcceptListener() {
116 public void onAccept(Channel channel) {
117 RequestChannel requestChannel = null;
118 try {
119 SyncChannel syncChannel = AsyncToSyncChannel.adapt(channel);
120 SocketMetadata socket = (SocketMetadata) syncChannel.narrow(SocketMetadata.class);
121 socket.setTcpNoDelay(true);
122
123 requestChannel = createRequestChannel(syncChannel);
124
125 RequestChannelInterceptorInvoker invoker = new RequestChannelInterceptorInvoker(loginServiceInterceptor, loginService.getClass().getClassLoader());
126 requestChannel.setRequestListener(invoker);
127 requestChannel.start();
128 } catch (IOException e) {
129 log.warn("Failed to accept connection.", e);
130 if (requestChannel != null)
131 requestChannel.dispose();
132 else
133 channel.dispose();
134 }
135 }
136
137 public void onAcceptError(IOException error) {
138 log.warn("Accept Failed: " + error);
139 }
140 });
141
142 server.start();
143 log.debug("Remote login service started on: " + server.getConnectURI() + " clients can connect to: " + server.getConnectURI());
144 }
145
146 private AsyncChannelServer createAsyncChannelServer() throws IOException, URISyntaxException {
147 SocketSyncChannelFactory factory = new SocketSyncChannelFactory();
148 SyncChannelServer server = factory.bindSyncChannel(new URI(protocol, null, host, port, null, null, null));
149 return new SyncToAsyncChannelServer(server);
150 }
151
152 private RequestChannel createRequestChannel(SyncChannel channel) throws IOException {
153
154 return new AsyncChannelToServerRequestChannel(new PacketAggregatingAsyncChannel(SyncToAsyncChannel.adapt(channel))) {
155 /**
156 * close out the channel once one request has been serviced.
157 */
158 public void onPacket(Packet packet) {
159 super.onPacket(packet);
160 dispose();
161 }
162 };
163 }
164
165 public void doStop() {
166 server.dispose();
167 server = null;
168 log.debug("Stopped remote login service.");
169 }
170
171 public void doFail() {
172 if (server != null) {
173 server.dispose();
174 server = null;
175 }
176 log.warn("Failed remote login service.");
177 }
178
179 public static final GBeanInfo GBEAN_INFO;
180
181 static {
182 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("Remote Login Listener", JaasLoginServiceRemotingServer.class);
183 infoFactory.addAttribute("clientConnectURI", URI.class, false);
184 infoFactory.addReference("LoginService", JaasLoginServiceMBean.class, "JaasLoginService");
185 infoFactory.addInterface(NetworkConnector.class, new String[]{"host", "port", "protocol"}, new String[]{"host", "port"});
186 infoFactory.setConstructor(new String[]{"protocol", "host", "port", "LoginService"});
187 GBEAN_INFO = infoFactory.getBeanInfo();
188 }
189
190 public static GBeanInfo getGBeanInfo() {
191 return GBEAN_INFO;
192 }
193 }