/* * 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.felix.jaas.internal; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.security.auth.spi.LoginModule; import org.apache.sling.commons.osgi.ManifestHeader; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.service.log.LogService; import org.osgi.util.tracker.BundleTracker; class BundleLoginModuleCreator extends BundleTracker implements LoginModuleCreator { private static final String JAAS_MODULE_CLASS = "Jaas-ModuleClass"; private final Map<String, LoginModuleInfo> loginModuleInfo = new ConcurrentHashMap<String, LoginModuleInfo>(); private final Logger log; public BundleLoginModuleCreator(BundleContext context, Logger log) { super(context, Bundle.ACTIVE, null /* customizer */); this.log = log; } public LoginModule newInstance(String className) { LoginModuleInfo lmInfo = loginModuleInfo.get(className); //TODO Rethink about exception handling. Probably introduce custom exception classes if (lmInfo == null) { throw new AssertionError("No bundle exists to create LoginModule from " + className); } try { return lmInfo.newInstance(); } catch (IllegalAccessException e) { throw new RuntimeException("Error occurred while creating LoginModule for " + className, e); } catch (InstantiationException e) { throw new RuntimeException("Error occurred while creating LoginModule for " + className, e); } } public Map<Bundle, Set<String>> getBundleToLoginModuleMapping() { //With R5 we could have used Map<Bundle, T> BundleTracker.getTracked() //Determine the bundle -> login module classes map Map<Bundle, Set<String>> bundleMap = new HashMap<Bundle, Set<String>>(); for (LoginModuleInfo e : loginModuleInfo.values()) { Bundle b = e.getBundle(); @SuppressWarnings("unchecked") Set<String> classNames = (Set<String>) getObject(b); if (classNames == null) { continue; } bundleMap.put(b, classNames); } return bundleMap; } // ---------- BundleTracker integration ---------------------------------------------- @Override public Object addingBundle(Bundle bundle, BundleEvent event) { if (providesLoginModule(bundle)) { return registerBundle(bundle); } return null; } @Override public void removedBundle(Bundle bundle, BundleEvent event, Object object) { @SuppressWarnings("unchecked") Set<String> classNames = (Set<String>) object; for (String className : classNames) { loginModuleInfo.remove(className); } } private boolean providesLoginModule(Bundle bundle) { return bundle.getHeaders().get(JAAS_MODULE_CLASS) != null; } private Set<String> registerBundle(Bundle bundle) { Set<String> classNames = parseHeader((String) bundle.getHeaders().get( JAAS_MODULE_CLASS)); for (String className : classNames) { LoginModuleInfo bi = new LoginModuleInfo(className, bundle, log); if (bi.isValid()) { //Duplicate registration check if (loginModuleInfo.containsKey(className)) { LoginModuleInfo existingInfo = loginModuleInfo.get(className); String msg = String.format( "LoginModule class %s is already registered with Bundle %s. Entry " + "from bundle %s would be ignored", className, existingInfo.getBundle(), bundle); log.log(LogService.LOG_WARNING, msg); continue; } loginModuleInfo.put(className, bi); log.log(LogService.LOG_INFO, "Registering LoginModule class [" + className + "] from Bundle " + bundle); } else { log.log(LogService.LOG_WARNING, "Could not load LoginModule class " + bi.getClassName() + " from bundle " + bundle); } } return classNames; } static final class LoginModuleInfo { private final String className; private final Bundle bundle; private final Class<LoginModule> clazz; @SuppressWarnings("unchecked") public LoginModuleInfo(String className, Bundle bundle, Logger log) { this.className = className; this.bundle = bundle; Class<LoginModule> clazz = null; try { clazz = bundle.loadClass(className); } catch (ClassNotFoundException e) { log.log(LogService.LOG_WARNING, "Error loading class [" + className + "] from bundle " + bundle, e); } this.clazz = clazz; } public LoginModule newInstance() throws IllegalAccessException, InstantiationException { if (clazz == null) { throw new IllegalStateException("LoginModule class not initialized"); } return clazz.newInstance(); } public boolean isValid() { return clazz != null; } public String getClassName() { return className; } public Bundle getBundle() { return bundle; } } private static Set<String> parseHeader(String header) { Set<String> values = new HashSet<String>(); ManifestHeader mh = ManifestHeader.parse(header); for(ManifestHeader.Entry e : mh.getEntries()) { values.add(e.getValue()); } return values; } }