001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * bstefanescu 011 */ 012package org.nuxeo.runtime.api; 013 014import java.util.Map; 015 016import javax.security.auth.Subject; 017import javax.security.auth.callback.CallbackHandler; 018import javax.security.auth.login.LoginException; 019import javax.security.auth.spi.LoginModule; 020 021/** 022 * A login module wrapper to overcome the class loading issues on OSGi frameworks. 023 * <p> 024 * A login module is specified using the class name - and when doing a login against that module the login context will 025 * get a class instance for the module by using Clas.forName and the current thread context class loader. This means in 026 * an OSGi application the class loader of the caller bundle will be used to resolve the login module. But the caller 027 * bundle may not have any dependency on the login module since it is not aware about which login module implementation 028 * is used underneath - so in most cases the login module class will not be found. 029 * <p> 030 * For this reason all the contributed login modules will be wrapped using this class. As almost any Nuxeo bundle have a 031 * dependency on runtime this class will be visible from almost any Nuxeo bundle. So, the login context will instantiate 032 * this wrapper instead of the real login module and the wrapper will use OSGi logic to instantiate the wrapped login 033 * module. (by using the bundle that contributed the login module) 034 * <p> 035 * <b>IMPORTANT</b> 036 * <p> 037 * This class is in org.nuxeo.runtime.api package to be visible to any bundle that uses Nuxeo runtime. This is because 038 * this package is imported by almost any bundle using Nuxeo runtime - so you don't need to declare the import package 039 * in the OSGi manifest. In the case you don't use runtime but you are doing logins in the context of your bundle you 040 * must import the package <code>org.nuxeo.runtime.api</code> in your manifest. 041 * 042 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 043 */ 044public class LoginModuleWrapper implements LoginModule { 045 046 public static final String DELEGATE_CLASS_KEY = LoginModuleWrapper.class.getName() + ".delegate"; 047 048 protected LoginModule delegate; 049 050 protected void initDelegate(Map<String, ?> options) { 051 if (delegate == null) { 052 try { 053 Class<?> clazz = (Class<?>) options.get(DELEGATE_CLASS_KEY); 054 delegate = (LoginModule) clazz.newInstance(); 055 } catch (NullPointerException e) { 056 throw new RuntimeException("Should be a bug: No DELEGATE_CLASS_KEY found in login module options", e); 057 } catch (ReflectiveOperationException e) { 058 throw new RuntimeException("Invalid login module class: " + options.get(DELEGATE_CLASS_KEY) 059 + ". Should implement LoginModule.", e); 060 } 061 } 062 } 063 064 @Override 065 public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, 066 Map<String, ?> options) { 067 initDelegate(options); 068 delegate.initialize(subject, callbackHandler, sharedState, options); 069 } 070 071 @Override 072 public boolean login() throws LoginException { 073 return delegate.login(); 074 } 075 076 @Override 077 public boolean commit() throws LoginException { 078 return delegate.commit(); 079 } 080 081 @Override 082 public boolean abort() throws LoginException { 083 return delegate.abort(); 084 } 085 086 @Override 087 public boolean logout() throws LoginException { 088 return delegate.logout(); 089 } 090 091}