/* * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * bstefanescu */ package org.nuxeo.runtime.api; import java.util.Map; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; /** * A login module wrapper to overcome the class loading issues on OSGi frameworks. * <p> * A login module is specified using the class name - and when doing a login against that module the login context will * get a class instance for the module by using Clas.forName and the current thread context class loader. This means in * an OSGi application the class loader of the caller bundle will be used to resolve the login module. But the caller * bundle may not have any dependency on the login module since it is not aware about which login module implementation * is used underneath - so in most cases the login module class will not be found. * <p> * For this reason all the contributed login modules will be wrapped using this class. As almost any Nuxeo bundle have a * dependency on runtime this class will be visible from almost any Nuxeo bundle. So, the login context will instantiate * this wrapper instead of the real login module and the wrapper will use OSGi logic to instantiate the wrapped login * module. (by using the bundle that contributed the login module) * <p> * <b>IMPORTANT</b> * <p> * This class is in org.nuxeo.runtime.api package to be visible to any bundle that uses Nuxeo runtime. This is because * this package is imported by almost any bundle using Nuxeo runtime - so you don't need to declare the import package * in the OSGi manifest. In the case you don't use runtime but you are doing logins in the context of your bundle you * must import the package <code>org.nuxeo.runtime.api</code> in your manifest. * * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> */ public class LoginModuleWrapper implements LoginModule { public static final String DELEGATE_CLASS_KEY = LoginModuleWrapper.class.getName() + ".delegate"; protected LoginModule delegate; protected void initDelegate(Map<String, ?> options) { if (delegate == null) { try { Class<?> clazz = (Class<?>) options.get(DELEGATE_CLASS_KEY); delegate = (LoginModule) clazz.newInstance(); } catch (NullPointerException e) { throw new RuntimeException("Should be a bug: No DELEGATE_CLASS_KEY found in login module options", e); } catch (ReflectiveOperationException e) { throw new RuntimeException("Invalid login module class: " + options.get(DELEGATE_CLASS_KEY) + ". Should implement LoginModule.", e); } } } @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) { initDelegate(options); delegate.initialize(subject, callbackHandler, sharedState, options); } @Override public boolean login() throws LoginException { return delegate.login(); } @Override public boolean commit() throws LoginException { return delegate.commit(); } @Override public boolean abort() throws LoginException { return delegate.abort(); } @Override public boolean logout() throws LoginException { return delegate.logout(); } }