1 /**
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.geronimo.client;
19
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.security.PrivilegedAction;
24
25 import javax.security.auth.Subject;
26 import javax.security.auth.callback.CallbackHandler;
27 import javax.security.auth.login.LoginContext;
28 import javax.security.auth.login.LoginException;
29
30 import org.apache.geronimo.gbean.AbstractName;
31 import org.apache.geronimo.gbean.GBeanInfo;
32 import org.apache.geronimo.gbean.GBeanInfoBuilder;
33 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
34 import org.apache.geronimo.kernel.Kernel;
35 import org.apache.geronimo.security.ContextManager;
36 import org.apache.geronimo.security.Callers;
37 import org.apache.geronimo.security.deploy.DefaultPrincipal;
38 import org.apache.geronimo.security.util.ConfigurationUtil;
39
40 /**
41 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
42 */
43 public final class AppClientContainer {
44 private static final Class[] MAIN_ARGS = {String[].class};
45
46 private final String mainClassName;
47 private final AppClientPlugin jndiContext;
48 private final AbstractName appClientModuleName;
49 private final String realmName;
50 private final Class callbackHandlerClass;
51 private final Subject defaultSubject;
52 private final Method mainMethod;
53 private final ClassLoader classLoader;
54 private final Kernel kernel;
55
56 public AppClientContainer(String mainClassName,
57 AbstractName appClientModuleName,
58 String realmName,
59 String callbackHandlerClassName,
60 DefaultPrincipal defaultPrincipal,
61 AppClientPlugin jndiContext,
62 ClassLoader classLoader,
63 Kernel kernel
64 ) throws Exception {
65 this.mainClassName = mainClassName;
66 this.appClientModuleName = appClientModuleName;
67 if ((realmName == null) != (callbackHandlerClassName == null)) {
68 throw new IllegalArgumentException("You must supply both realmName and callbackHandlerClass or neither");
69 }
70 this.realmName = realmName;
71 if (callbackHandlerClassName != null) {
72 try {
73 this.callbackHandlerClass = classLoader.loadClass(callbackHandlerClassName);
74 } catch (ClassNotFoundException e) {
75 throw new AppClientInitializationException("Could not load callbackHandlerClass", e);
76 }
77 } else {
78 callbackHandlerClass = null;
79 }
80 if (defaultPrincipal != null) {
81 defaultSubject = ConfigurationUtil.generateDefaultSubject(defaultPrincipal, classLoader);
82 } else {
83 defaultSubject = null;
84 }
85 this.classLoader = classLoader;
86 this.kernel = kernel;
87 this.jndiContext = jndiContext;
88
89 try {
90 Class mainClass = classLoader.loadClass(mainClassName);
91 mainMethod = mainClass.getMethod("main", MAIN_ARGS);
92 } catch (ClassNotFoundException e) {
93 throw new AppClientInitializationException("Unable to load Main-Class " + mainClassName, e);
94 } catch (NoSuchMethodException e) {
95 throw new AppClientInitializationException("Main-Class " + mainClassName + " does not have a main method", e);
96 }
97 }
98
99 public AbstractName getAppClientModuleName() {
100 return appClientModuleName;
101 }
102
103 public String getMainClassName() {
104 return mainClassName;
105 }
106
107 public void main(final String[] args) throws Exception {
108
109
110 Thread thread = Thread.currentThread();
111
112 ClassLoader oldClassLoader = thread.getContextClassLoader();
113 Callers oldCallers = ContextManager.getCallers();
114 Subject clientSubject = defaultSubject;
115 LoginContext loginContext = null;
116 try {
117 thread.setContextClassLoader(classLoader);
118 if (callbackHandlerClass != null) {
119
120 CallbackHandler callbackHandler;
121 try {
122 Constructor cArgs = callbackHandlerClass.getConstructor(new Class[] {String[].class});
123 callbackHandler = (CallbackHandler) cArgs.newInstance(new Object[] {args});
124 } catch (NoSuchMethodException e) {
125 callbackHandler = (CallbackHandler) callbackHandlerClass.newInstance();
126 }
127 loginContext = new LoginContext(realmName, callbackHandler);
128 try {
129 loginContext.login();
130 } catch (LoginException e) {
131 loginContext = null;
132 throw e;
133 }
134 clientSubject = loginContext.getSubject();
135 }
136 ContextManager.setCallers(clientSubject, clientSubject);
137 jndiContext.startClient(appClientModuleName, kernel, classLoader);
138 if (clientSubject == null) {
139 mainMethod.invoke(null, new Object[]{args});
140 } else {
141 Subject.doAs(clientSubject, new PrivilegedAction() {
142 public Object run() {
143 try {
144 mainMethod.invoke(null, new Object[]{args});
145 } catch (IllegalAccessException e) {
146 throw new RuntimeException(e);
147 } catch (InvocationTargetException e) {
148 throw new RuntimeException(e);
149 }
150 return null;
151 }
152 });
153 }
154 } catch (InvocationTargetException e) {
155 Throwable cause = e.getCause();
156 if (cause instanceof Exception) {
157 throw (Exception) cause;
158 } else if (cause instanceof Error) {
159 throw (Error) cause;
160 }
161 throw new Error(e);
162 } finally {
163 if (loginContext != null) {
164 loginContext.logout();
165 }
166 jndiContext.stopClient(appClientModuleName);
167
168 thread.setContextClassLoader(oldClassLoader);
169 ContextManager.popCallers(oldCallers);
170 }
171 }
172
173 public static final GBeanInfo GBEAN_INFO;
174
175 static {
176 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(AppClientContainer.class, NameFactory.APP_CLIENT);
177
178 infoFactory.addOperation("main", new Class[]{String[].class});
179
180 infoFactory.addAttribute("mainClassName", String.class, true);
181 infoFactory.addAttribute("appClientModuleName", AbstractName.class, true);
182 infoFactory.addAttribute("realmName", String.class, true);
183 infoFactory.addAttribute("callbackHandlerClassName", String.class, true);
184 infoFactory.addAttribute("defaultPrincipal", DefaultPrincipal.class, true);
185
186 infoFactory.addReference("JNDIContext", AppClientPlugin.class, NameFactory.GERONIMO_SERVICE);
187
188 infoFactory.addAttribute("classLoader", ClassLoader.class, false);
189 infoFactory.addAttribute("kernel", Kernel.class, false);
190
191
192 infoFactory.setConstructor(new String[]{"mainClassName",
193 "appClientModuleName",
194 "realmName",
195 "callbackHandlerClassName",
196 "defaultPrincipal",
197 "JNDIContext",
198 "classLoader",
199 "kernel"
200 });
201
202 GBEAN_INFO = infoFactory.getBeanInfo();
203 }
204
205 public static GBeanInfo getGBeanInfo() {
206 return GBEAN_INFO;
207 }
208 }