/*
* Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* bstefanescu
*/
package org.eclipse.ecr.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.eclipse.ecr.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.eclipse.ecr.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 (ClassCastException e) {
throw new RuntimeException("Invalid login module class: "+options.get(DELEGATE_CLASS_KEY)+". Should implement LoginModule.", e);
} catch (Exception e) {
throw new RuntimeException("Cannot instantiate login module: "+options.get(DELEGATE_CLASS_KEY), 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();
}
}