/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.openejb.core.security.jaas;
import org.apache.openejb.AppContext;
import org.apache.openejb.OpenEJBRuntimeException;
import org.apache.openejb.core.WebContext;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.spi.ContainerSystem;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.container.BeanManagerImpl;
import org.apache.webbeans.context.creational.CreationalContextImpl;
import org.apache.webbeans.inject.OWBInjector;
import javax.enterprise.inject.spi.Bean;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import java.util.Map;
import java.util.Set;
/**
* Usage:
* <p/>
* CDI {
* org.apache.openejb.core.security.jaas.CDILoginModule required
* delegate="org.apache.openejb.core.security.CDILoginModuleTest$Delegate"
* loginModuleAsCdiBean=false
* cdiName="xxx";
* };
* <p/>
* Note: you can use instead of delegate <appid> to define a delegate by app.
* Note 2: loginModuleAsCdiBean=true is recommanded only for @Dependent beans
* Note 3: delegate and cdiName can be used alone
*/
public class CDILoginModule implements LoginModule {
private CreationalContextImpl<?> cc;
private LoginModule loginModule;
@Override
public void initialize(final Subject subject, final CallbackHandler callbackHandler,
final Map<String, ?> sharedState, final Map<String, ?> options) {
final WebBeansContext webBeansContext = WebBeansContext.currentInstance();
final BeanManagerImpl bm = webBeansContext.getBeanManagerImpl();
if (!bm.isInUse()) {
throw new OpenEJBRuntimeException("CDI not activated");
}
String delegate = String.valueOf(options.get("delegate"));
if ("null".equals(delegate)) {
final String app = findAppName(webBeansContext);
delegate = String.valueOf(options.get(app));
if ("null".equals(delegate)) {
throw new OpenEJBRuntimeException("Please specify a delegate class");
}
}
final Class<?> clazz;
try {
clazz = Thread.currentThread().getContextClassLoader().loadClass(delegate);
} catch (final ClassNotFoundException e) {
throw new OpenEJBRuntimeException(e.getMessage(), e);
}
cc = bm.createCreationalContext(null);
final String cdiName = String.valueOf(options.get("cdiName"));
if ("true".equals(String.valueOf(options.get("loginModuleAsCdiBean")))) {
final Set<Bean<?>> beans;
if ("null".equals(cdiName)) {
beans = bm.getBeans(clazz);
} else {
beans = bm.getBeans(cdiName);
}
loginModule = LoginModule.class.cast(bm.getReference(bm.resolve(beans), clazz, cc));
} else {
try {
loginModule = LoginModule.class.cast(clazz.newInstance());
OWBInjector.inject(bm, loginModule, cc);
} catch (final Exception e) {
throw new OpenEJBRuntimeException("Can't inject into delegate class " + loginModule, e);
}
}
loginModule.initialize(subject, callbackHandler, sharedState, options);
}
private static String findAppName(final WebBeansContext webBeansContext) {
final ContainerSystem containerSystem = SystemInstance.get().getComponent(ContainerSystem.class);
for (final AppContext appContext : containerSystem.getAppContexts()) {
if (appContext.getWebBeansContext() == webBeansContext) {
return appContext.getId();
}
for (final WebContext web : appContext.getWebContexts()) {
if (web.getWebbeansContext() == webBeansContext) { // ear
return web.getId();
}
}
}
return "defaultDelegate";
}
@Override
public boolean login() throws LoginException {
return loginModule != null && loginModule.login();
}
@Override
public boolean commit() throws LoginException {
return loginModule == null || loginModule.commit(); // cleanUp is called on logout
}
@Override
public boolean abort() throws LoginException {
try {
return loginModule == null || loginModule.abort();
} finally {
cleanUp();
}
}
@Override
public boolean logout() throws LoginException {
try {
return loginModule == null || loginModule.logout();
} finally {
cleanUp();
}
}
private void cleanUp() {
if (cc != null) {
cc.release();
cc = null;
}
}
}