001 /** 002 * 003 * Copyright 2004 The Apache Software Foundation 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.geronimo.security.remoting.jmx; 019 020 import java.io.IOException; 021 import java.net.InetSocketAddress; 022 import java.net.URI; 023 import java.net.URISyntaxException; 024 import javax.management.ObjectName; 025 import org.activeio.AcceptListener; 026 import org.activeio.AsyncChannelServer; 027 import org.activeio.Channel; 028 import org.activeio.Packet; 029 import org.activeio.RequestChannel; 030 import org.activeio.SyncChannel; 031 import org.activeio.SyncChannelServer; 032 import org.activeio.adapter.AsyncChannelToServerRequestChannel; 033 import org.activeio.adapter.AsyncToSyncChannel; 034 import org.activeio.adapter.SyncToAsyncChannel; 035 import org.activeio.adapter.SyncToAsyncChannelServer; 036 import org.activeio.filter.PacketAggregatingAsyncChannel; 037 import org.activeio.net.SocketMetadata; 038 import org.activeio.net.SocketSyncChannelFactory; 039 import org.apache.commons.logging.Log; 040 import org.apache.commons.logging.LogFactory; 041 import org.apache.geronimo.gbean.GBeanInfo; 042 import org.apache.geronimo.gbean.GBeanInfoBuilder; 043 import org.apache.geronimo.gbean.GBeanLifecycle; 044 import org.apache.geronimo.kernel.ObjectNameUtil; 045 import org.apache.geronimo.management.geronimo.NetworkConnector; 046 import org.apache.geronimo.security.jaas.server.JaasLoginServiceMBean; 047 048 049 /** 050 * A server-side utility that exposes a JaasLoginService to remote clients. 051 * It prevents clients from connecting to arbitrary server-side MBeans through 052 * this listener -- only the JaasLoginService is exposed. 053 * 054 * @version $Rev: 417891 $ $Date: 2006-06-28 15:45:07 -0700 (Wed, 28 Jun 2006) $ 055 */ 056 public class JaasLoginServiceRemotingServer implements GBeanLifecycle, NetworkConnector { 057 058 public static final ObjectName REQUIRED_OBJECT_NAME = ObjectNameUtil.getObjectName("geronimo.remoting:target=JaasLoginServiceRemotingServer"); 059 060 private static final Log log = LogFactory.getLog(JaasLoginServiceRemotingServer.class); 061 private AsyncChannelServer server; 062 private JaasLoginServiceMBean loginService; 063 private String protocol; 064 private String host; 065 private int port; 066 067 public JaasLoginServiceRemotingServer(String protocol, String host, int port, JaasLoginServiceMBean loginService) { 068 this.protocol = protocol; 069 this.host = host; 070 this.port = port; 071 this.loginService = loginService; 072 } 073 074 public String getProtocol() { 075 return protocol; 076 } 077 078 public void setProtocol(String protocol) { 079 this.protocol = protocol; 080 } 081 082 public String getHost() { 083 return host; 084 } 085 086 public void setHost(String host) { 087 this.host = host; 088 } 089 090 public int getPort() { 091 return port; 092 } 093 094 public void setPort(int port) { 095 this.port = port; 096 } 097 098 public URI getClientConnectURI() { 099 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 }