View Javadoc

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); //has fixed name, j2eeType is irrelevant
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 }