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