All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.jaspic.config.factory.BaseAuthConfigFactory Maven / Gradle / Ivy

There is a newer version: 4.1.2.181
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.jaspic.config.factory;

import com.sun.jaspic.config.helper.JASPICLogManager;
import java.lang.reflect.Constructor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.security.auth.message.config.AuthConfigFactory;
import javax.security.auth.message.config.AuthConfigProvider;
import javax.security.auth.message.config.RegistrationListener;


/**
 * This class implements methods in the abstract class AuthConfigFactory.
 * @author  Shing Wai Chan
 */
public abstract class BaseAuthConfigFactory extends AuthConfigFactory {

    private static final Logger logger =
            Logger.getLogger(JASPICLogManager.JASPIC_LOGGER, JASPICLogManager.RES_BUNDLE);


    private static final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
    public static final Lock rLock = rwLock.readLock();
    public static final Lock wLock = rwLock.writeLock();

    private static Map id2ProviderMap;
    private static Map id2RegisContextMap;
    private static Map> id2RegisListenersMap;
    private static Map> provider2IdsMap;

    protected static final String CONF_FILE_NAME = "auth.conf";

    abstract protected RegStoreFileParser getRegStore();

    /**
     * Get a registered AuthConfigProvider from the factory.
     *
     * Get the provider of ServerAuthConfig and/or
     * ClientAuthConfig objects registered for the identified message
     * layer and application context.
     *
     * @param layer a String identifying the message layer
     *		for which the registered AuthConfigProvider is
     *          to be returned. This argument may be null.
     *
     * @param appContext a String that identifies the application messaging
     *          context for which the registered AuthConfigProvider
     *          is to be returned. This argument may be null.
     *
     * @param listener the RegistrationListener whose
     *          notify method is to be invoked
     *          if the corresponding registration is unregistered or
     *          replaced. The value of this argument may be null.
     *
     * @return the implementation of the AuthConfigProvider interface
     *          registered at the factory for the layer and appContext
     *          or null if no AuthConfigProvider is selected.
     *
     * 

All factories shall employ the following precedence rules to select * the registered AuthConfigProvider that matches (via matchConstructors) the * layer and appContext arguments: *

    *
  • The provider that is specifically registered for both the * corresponding message layer and appContext * shall be selected. *
  • if no provider is selected according to the preceding rule, * the provider specifically registered for the * corresponding appContext and for all message layers * shall be selected. *
  • if no provider is selected according to the preceding rules, * the provider specifically registered for the * corresponding message layer and for all appContexts * shall be selected. *
  • if no provider is selected according to the preceding rules, * the provider registered for all message layers and for all * appContexts shall be selected. *
  • if no provider is selected according to the preceding rules, * the factory shall terminate its search for a registered provider. *
*/ @Override public AuthConfigProvider getConfigProvider(String layer, String appContext, RegistrationListener listener) { AuthConfigProvider provider = null; if (listener == null) { rLock.lock(); try { provider = getConfigProviderUnderLock(layer,appContext,null); } finally { rLock.unlock(); } } else { wLock.lock(); try { provider = getConfigProviderUnderLock(layer,appContext,listener); } finally { wLock.unlock(); } } return provider; } /** * Registers within the factory, a provider * of ServerAuthConfig and/or ClientAuthConfig objects for a * message layer and application context identifier. * *

At most one registration may exist within the factory for a * given combination of message layer * and appContext. Any pre-existing * registration with identical values for layer and appContext is replaced * by a subsequent registration. When replacement occurs, the registration * identifier, layer, and appContext identifier remain unchanged, * and the AuthConfigProvider (with initialization properties) and * description are replaced. * *

Within the lifetime of its Java process, a factory must assign unique * registration identifiers to registrations, and must never * assign a previously used registration identifier to a registration * whose message layer and or appContext identifier differ from * the previous use. * *

Programmatic registrations performed via this method must update * (according to the replacement rules described above), the persistent * declarative representation of provider registrations employed by the * factory constructor. * * @param className the fully qualified name of an AuthConfigProvider * implementation class. This argument must not be null. * * @param properties a Map object containing the initialization * properties to be passed to the provider constructor. * This argument may be null. When this argument is not null, * all the values and keys occuring in the Map must be of * type String. * * @param layer a String identifying the message layer * for which the provider will be registered at the factory. * A null value may be passed as an argument for this parameter, * in which case, the provider is registered at all layers. * * @param appContext a String value that may be used by a runtime * to request a configuration object from this provider. * A null value may be passed as an argument for this parameter, * in which case, the provider is registered for all * configuration ids (at the indicated layers). * * @param description a text String describing the provider. * this value may be null. * * @return a String identifier assigned by * the factory to the provider registration, and that may be * used to remove the registration from the provider. * * @exception SecurityException if the caller does not have * permission to register a provider at the factory. * * @exception AuthException if the provider * construction or registration fails. */ @Override public String registerConfigProvider(String className, Map properties, String layer, String appContext, String description) { //XXX factory must check permission SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(AuthConfigFactory.providerRegistrationSecurityPermission); } //XXX do we need doPrivilege here AuthConfigProvider provider = _constructProvider(className, properties, null); return _register(provider,properties, layer,appContext,description,true); } @Override public String registerConfigProvider(AuthConfigProvider provider, String layer, String appContext, String description) { //XXX factory must check permission SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(AuthConfigFactory.providerRegistrationSecurityPermission); } return _register(provider,null,layer,appContext,description,false); } /** * Remove the identified provider registration from the factory * and invoke any listeners associated with the removed registration. * * @param registrationID a String that identifies a provider registration * at the factory * * @return true if there was a registration with the specified identifier * and it was removed. Return false if the registraionID was * invalid. * * @exception SecurityException if the caller does not have * permission to unregister the provider at the factory. * */ @Override public boolean removeRegistration(String registrationID) { //XXX factory must check permission SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(AuthConfigFactory.providerRegistrationSecurityPermission); } return _unRegister(registrationID); } /** * Disassociate the listener from all the provider * registrations whose layer and appContext values are matched * by the corresponding arguments to this method. * * @param listener the RegistrationListener to be detached. * * @param layer a String identifying the message layer or null. * * @param appContext a String value identifying the application context * or null. * * @return an array of String values where each value identifies a * provider registration from which the listener was removed. * This method never returns null; it returns an empty array if * the listener was not removed from any registrations. * * @exception SecurityException if the caller does not have * permission to detach the listener from the factory. * */ @Override public String[] detachListener(RegistrationListener listener, String layer, String appContext) { //XXX factory must check permission SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(AuthConfigFactory.providerRegistrationSecurityPermission); } ArrayList list = new ArrayList(); String regisID = getRegistrationID(layer, appContext); wLock.lock(); try { Set targets = id2RegisListenersMap.keySet(); for (String targetID : targets) { if (regIdImplies(regisID, targetID)) { List listeners = id2RegisListenersMap.get(targetID); if (listeners != null && listeners.remove(listener)) { list.add(targetID); } } } } finally { wLock.unlock(); } return list.toArray(new String[list.size()]); } /** * Get the registration identifiers for all registrations of the * provider instance at the factory. * * @param provider the AuthConfigurationProvider whose registration * identifiers are to be returned. This argument may be * null, in which case, it indicates that the the id's of * all active registration within the factory are returned. * * @return an array of String values where each value identifies a * provider registration at the factory. This method never returns null; * it returns an empty array when their are no registrations at the * factory for the identified provider. */ @Override public String[] getRegistrationIDs(AuthConfigProvider provider) { rLock.lock(); try { Collection regisIDs = null; if (provider != null) { regisIDs = provider2IdsMap.get(provider); } else { Collection> collList = provider2IdsMap.values(); if (collList != null) { regisIDs = new HashSet(); for (List listIds : collList) { if (listIds != null) { regisIDs.addAll(listIds); } } } } return ((regisIDs != null)? regisIDs.toArray(new String[regisIDs.size()]) : new String[0]); } finally { rLock.unlock(); } } /** * Get the the registration context for the identified registration. * * @param registrationID a String that identifies a provider registration * at the factory * * @return a RegistrationContext or null. When a Non-null value is * returned, it is a copy of the registration context corresponding to the * registration. Null is returned when the registration identifier does * not correspond to an active registration */ @Override public RegistrationContext getRegistrationContext(String registrationID) { rLock.lock(); try { return id2RegisContextMap.get(registrationID); } finally { rLock.unlock(); } } /** * Cause the factory to reprocess its persistent declarative * representation of provider registrations. * *

A factory should only replace an existing registration when * a change of provider implementation class or initialization * properties has occurred. * * @exception AuthException if an error occurred during the * reinitialization. * * @exception SecurityException if the caller does not have permission * to refresh the factory. */ @Override public void refresh() { //XXX factory must check permission SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(AuthConfigFactory.providerRegistrationSecurityPermission); } Map> preExistingListenersMap; wLock.lock(); try { preExistingListenersMap = id2RegisListenersMap; _loadFactory(); } finally { wLock.unlock(); } // notify pre-existing listeners after (re)loading factory if (preExistingListenersMap != null) { notifyListeners(preExistingListenersMap); } } private AuthConfigProvider getConfigProviderUnderLock(String layer, String appContext, RegistrationListener listener) { AuthConfigProvider provider = null; String regisID = getRegistrationID(layer, appContext); String matchedID = null; boolean providerFound = false; if (id2ProviderMap.containsKey(regisID)) { provider = id2ProviderMap.get(regisID); providerFound = true; } if (!providerFound) { matchedID = getRegistrationID(null, appContext); if (id2ProviderMap.containsKey(matchedID)) { provider = id2ProviderMap.get(matchedID); providerFound = true; } } if (!providerFound) { matchedID = getRegistrationID(layer, null); if (id2ProviderMap.containsKey(matchedID)) { provider = id2ProviderMap.get(matchedID); providerFound = true; } } if (!providerFound) { matchedID = getRegistrationID(null, null); if (id2ProviderMap.containsKey(matchedID)) { provider = id2ProviderMap.get(matchedID); } } if (listener != null) { List listeners = id2RegisListenersMap.get(regisID); if (listeners == null) { listeners = new ArrayList(); id2RegisListenersMap.put(regisID, listeners); } if (!listeners.contains(listener)) { listeners.add(listener); } } return provider; } private static String getRegistrationID(String layer, String appContext) { String regisID = null; // __0 (null, null) // __1 (null, appContext) // __2 (layer, null) // __3_ (layer, appContext) if (layer != null) { regisID = (appContext != null) ? "__3" + layer.length() + "_" + layer + appContext : "__2" + layer; } else { regisID = (appContext != null) ? "__1" + appContext : "__0"; } return regisID; } /** * This API decomposes the given regisID into layer and appContext. * @param regisID * @return a String array with layer and appContext */ private static String[] decomposeRegisID(String regisID) { String layer = null; String appContext = null; if (regisID.equals("__0")) { // null, null } else if (regisID.startsWith("__1")) { appContext = (regisID.length() == 3)? "" : regisID.substring(3); } else if (regisID.startsWith("__2")) { layer = (regisID.length() == 3)? "" : regisID.substring(3); } else if (regisID.startsWith("__3")) { int ind = regisID.indexOf('_', 3); if (regisID.length() > 3 && ind > 0) { String numberString = regisID.substring(3, ind); int n; try { n = Integer.parseInt(numberString); } catch (Exception ex) { throw new IllegalArgumentException(); } layer = regisID.substring(ind + 1, ind + 1 + n); appContext = regisID.substring(ind + 1 + n); } else { throw new IllegalArgumentException(); } } else { throw new IllegalArgumentException(); } return new String[]{layer, appContext}; } private static AuthConfigProvider _constructProvider (String className, Map properties, AuthConfigFactory factory) { //XXX do we need doPrivilege here AuthConfigProvider provider = null; if (className != null) { try { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class c = Class.forName(className, true, loader); Constructor constr = c.getConstructor(Map.class, AuthConfigFactory.class); provider = constr.newInstance (new Object[]{properties, factory}); } catch (Throwable t) { Throwable cause = t.getCause(); logger.log(Level.WARNING, "jmac.factory_unable_to_load_provider", new Object[]{ className, t.toString(), (cause == null ? "cannot determine" : cause.toString())}); } } return provider; } //XXX need to update persistent state and notify effected listeners private String _register(AuthConfigProvider provider, Map properties, String layer, String appContext, String description, boolean persistent) { String regisID = getRegistrationID(layer, appContext); RegistrationContext rc = new RegistrationContextImpl(layer, appContext, description, persistent); RegistrationContext prevRegisContext = null; Map> listenerMap; wLock.lock(); try { prevRegisContext = id2RegisContextMap.get(regisID); AuthConfigProvider prevProvider = id2ProviderMap.get(regisID); // handle the persistence first - so that any exceptions occur before // the actual registration happens if (persistent) { _storeRegistration(regisID, rc, provider, properties); } else if (prevRegisContext != null && prevRegisContext.isPersistent()) { _deleteStoredRegistration(regisID, prevRegisContext); } boolean wasRegistered = id2ProviderMap.containsKey(regisID); if (wasRegistered) { List prevRegisIDs = provider2IdsMap.get(prevProvider); prevRegisIDs.remove(regisID); if (prevRegisIDs.isEmpty()) { provider2IdsMap.remove(prevProvider); } } id2ProviderMap.put(regisID, provider); id2RegisContextMap.put(regisID, rc); List regisIDs = provider2IdsMap.get(provider); if (regisIDs == null) { regisIDs = new ArrayList(); provider2IdsMap.put(provider, regisIDs); } if (!regisIDs.contains(regisID)) { regisIDs.add(regisID); } listenerMap = getEffectedListeners(regisID); } finally { wLock.unlock(); } // outside wLock to prevent dead lock notifyListeners(listenerMap); return regisID; } //XXX need to update persistent state and notify effected listeners private boolean _unRegister(String regisID) { boolean rvalue = false; RegistrationContext rc = null; Map> listenerMap; wLock.lock(); try { rc = id2RegisContextMap.remove(regisID); rvalue = id2ProviderMap.containsKey(regisID); AuthConfigProvider provider = id2ProviderMap.remove(regisID); List regisIDs = provider2IdsMap.get(provider); if (regisIDs != null) { regisIDs.remove(regisID); } if (regisIDs == null || regisIDs.isEmpty()) { provider2IdsMap.remove(provider); } if (!rvalue) { return false; } listenerMap = getEffectedListeners(regisID); if (rc != null && rc.isPersistent()) { _deleteStoredRegistration(regisID, rc); } } finally { wLock.unlock(); } // outside wLock to prevent dead lock notifyListeners(listenerMap); return rvalue; } // the following methods implement the factory's persistence layer protected void _loadFactory() { try { initializeMaps(); List entryList = getRegStore().getPersistedEntries(); for (EntryInfo info : entryList) { if (info.isConstructorEntry()) { _constructProvider(info.getClassName(), info.getProperties(), this); } else { boolean first = true; AuthConfigProvider p = null; List contexts = (info.getRegContexts()); for (RegistrationContext ctx : contexts) { if (first) { p = _constructProvider(info.getClassName(), info.getProperties(), null); } _loadRegistration(p, ctx.getMessageLayer(), ctx.getAppContext(), ctx.getDescription()); } } } } catch (Exception e) { if (logger.isLoggable(Level.WARNING)) { logger.log(Level.WARNING, "jmac.factory_auth_config_loader_failure", e); } } } /** * Initialize the static maps in a static method */ private static void initializeMaps() { id2ProviderMap = new HashMap(); id2RegisContextMap = new HashMap(); id2RegisListenersMap = new HashMap>(); provider2IdsMap = new HashMap>(); } private static String _loadRegistration(AuthConfigProvider provider, String layer, String appContext, String description) { RegistrationContext rc = new RegistrationContextImpl(layer, appContext, description, true); String regisID = getRegistrationID(layer, appContext); id2RegisContextMap.get(regisID); AuthConfigProvider prevProvider = id2ProviderMap.get(regisID); boolean wasRegistered = id2ProviderMap.containsKey(regisID); if (wasRegistered) { List prevRegisIDs = provider2IdsMap.get(prevProvider); prevRegisIDs.remove(regisID); if (prevRegisIDs.isEmpty()) { provider2IdsMap.remove(prevProvider); } } id2ProviderMap.put(regisID, provider); id2RegisContextMap.put(regisID, rc); List regisIDs = provider2IdsMap.get(provider); if (regisIDs == null) { regisIDs = new ArrayList(); provider2IdsMap.put(provider, regisIDs); } if (!regisIDs.contains(regisID)) { regisIDs.add(regisID); } return regisID; } private void _storeRegistration(String regId, RegistrationContext ctx, AuthConfigProvider p, Map properties) { String className = null; if (p != null) { className = p.getClass().getName(); } if (propertiesContainAnyNonStringValues(properties)) { throw new IllegalArgumentException("AuthConfigProvider cannot be registered - properties must all be of type String."); } if (ctx.isPersistent()) { getRegStore().store(className, ctx, properties); } } private boolean propertiesContainAnyNonStringValues(Map props) { if (props != null) { for(Map.Entry entry : props.entrySet()) { if (!(entry.getValue() instanceof String)) { return true; } } } return false; } private void _deleteStoredRegistration(String regId, RegistrationContext ctx) { if (ctx.isPersistent()) { getRegStore().delete(ctx); } } private static boolean regIdImplies(String reference, String target) { boolean rvalue = true; String[] refID = decomposeRegisID(reference); String[] targetID = decomposeRegisID(target); if (refID[0] != null && !refID[0].equals(targetID[0])) { rvalue = false; } else if (refID[1] != null && !refID[1].equals(targetID[1])) { rvalue = false; } return rvalue; } /* will return some extra listeners. iow, effected listeners could be reduced * by removing any associated with a provider registration id that is * more specific than the one being added or removed.l */ private static Map> getEffectedListeners(String regisID) { Map> effectedListeners = new HashMap>(); Set listenerRegistrations = new HashSet(id2RegisListenersMap.keySet()); for (String listenerID : listenerRegistrations) { if (regIdImplies(regisID, listenerID)) { if (!effectedListeners.containsKey(listenerID)) { effectedListeners.put(listenerID, new ArrayList()); } effectedListeners.get(listenerID).addAll(id2RegisListenersMap.remove(listenerID)); } } return effectedListeners; } private static void notifyListeners(Map> map) { Set>> entrySet = map.entrySet(); for (Map.Entry> entry : entrySet) { List listeners = map.get(entry.getKey()); if (listeners != null && listeners.size() > 0) { String[] dIds = decomposeRegisID(entry.getKey()); for (RegistrationListener listener : listeners) { listener.notify(dIds[0], dIds[1]); } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy