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

com.sun.enterprise.security.jauth.ConfigFile Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2011 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.
 */
// Portions Copyright [2018-2019] [Payara Foundation and/or its affiliates]
package com.sun.enterprise.security.jauth;

import java.io.*;
import java.util.*;

import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.AppConfigurationEntry;

import com.sun.enterprise.security.jaspic.config.ConfigParser;
import com.sun.enterprise.security.jaspic.config.GFServerConfigProvider;
import com.sun.logging.LogDomains;

/**
 * This is a default file-based AuthConfig implementation.
 *
 * @version %I%, %G%
 */
class ConfigFile extends AuthConfig {

    // indicates the age of the configuration approximately in
    // terms of the number of times refresh has been called
    private int epoch;

    // parser class name
    private String parserClassName;

    // parser
    private ConfigParser parser;

    // package private for ConfigFileParser
    static final String CLIENT = "client";
    static final String SERVER = "server";

    private static final String DEFAULT_HANDLER_CLASS = "com.sun.enterprise.security.jaspic.callback.ContainerCallbackHandler";

    private static final String DEFAULT_PARSER_CLASS = "com.sun.enterprise.security.jaspic.config.ConfigDomainParser";

    private static final Logger logger = LogDomains.getLogger(ConfigFile.class, LogDomains.SECURITY_LOGGER);

    ConfigFile() throws IOException {
        String propertyValue = System.getProperty("config.parser");
        if (propertyValue == null) {
            parserClassName = DEFAULT_PARSER_CLASS;
        } else {
            parserClassName = propertyValue;
        }
        this.epoch = 1;
        parser = ConfigFile.loadParser(parserClassName);
        parser.initialize(null);
    }

    /**
     * Get a default ClientAuthContext.
     *
     * @return an instance of ConfigClient.
     */
    @Override
    public ClientAuthContext getClientAuthContext(String intercept, String id, AuthPolicy requestPolicy, AuthPolicy responsePolicy,
            CallbackHandler handler) throws AuthException {

        ConfigFile.Entry[] entries = getEntries(intercept, id, requestPolicy, responsePolicy, CLIENT);
        if (entries == null || entries.length == 0) {
            return null;
        }

        // instantiate and initialize modules up front as well

        if (handler == null) {
            handler = ConfigFile.loadDefaultCallbackHandler();
        } else if (handler instanceof DependentCallbackHandler) {
            handler = new DelegatingHandler(handler);
        }

        for (int i = 0; i < entries.length; i++) {
            entries[i].module = ConfigFile.createModule(entries[i], handler);
        }

        return new ConfigClient(entries);
    }

    /**
     * Get a default ServerAuthContext.
     *
     * @return an instance of ConfigServer.
     */
    @Override
    public ServerAuthContext getServerAuthContext(String intercept, String id, AuthPolicy requestPolicy, AuthPolicy responsePolicy,
            CallbackHandler handler) throws AuthException {

        ConfigFile.Entry[] entries = getEntries(intercept, id, requestPolicy, responsePolicy, SERVER);
        if (entries == null || entries.length == 0) {
            return null;
        }

        // instantiate and initialize modules up front as well

        if (handler == null) {
            handler = ConfigFile.loadDefaultCallbackHandler();
        } else if (handler instanceof DependentCallbackHandler) {
            handler = new DelegatingHandler(handler);
        }

        for (int i = 0; i < entries.length; i++) {
            entries[i].module = ConfigFile.createModule(entries[i], handler);
        }

        return new ConfigServer(entries);
    }

    @Override
    public void refresh() throws AuthException {
        synchronized (this) {
            ConfigParser nextParser;
            int next = this.epoch + 1;
            try {
                nextParser = ConfigFile.loadParser(parserClassName);
            } catch (IOException ioe) {
                throw new AuthException(ioe.toString());
            }
            this.epoch = (next == 0 ? 1 : next);
            parser = nextParser;
        }
    }

    private ConfigFile.Entry[] getEntries(String intercept, String id, AuthPolicy requestPolicy, AuthPolicy responsePolicy, String type) {

        // get the parsed module config and DD information

        Map configMap;

        synchronized (parser) {
            configMap = parser.getConfigMap();
        }

        if (configMap == null) {
            return null;
        }

        // get the module config info for this intercept

        GFServerConfigProvider.InterceptEntry intEntry = (GFServerConfigProvider.InterceptEntry) configMap.get(intercept);
        if (intEntry == null || intEntry.getIdMap() == null) {
            if (logger != null && logger.isLoggable(Level.FINE)) {
                logger.fine("module config has no IDs configured for [" + intercept + "]");
            }
            return null;
        }

        // look up the DD's provider ID in the module config

        GFServerConfigProvider.IDEntry idEntry = null;
        if (id == null || (idEntry = intEntry.getIdMap().get(id)) == null) {

            // either the DD did not specify a provider ID,
            // or the DD-specified provider ID was not found
            // in the module config.
            //
            // in either case, look for a default ID in the module config

            if (logger != null && logger.isLoggable(Level.FINE)) {
                logger.fine("DD did not specify ID, " + "or DD-specified ID for [" + intercept + "] not found in config -- "
                        + "attempting to look for default ID");
            }

            String defaultID;
            if (CLIENT.equals(type)) {
                defaultID = intEntry.getDefaultClientID();
            } else {
                defaultID = intEntry.getDefaultServerID();
            }

            idEntry = intEntry.getIdMap().get(defaultID);
            if (idEntry == null) {

                // did not find a default provider ID

                if (logger != null && logger.isLoggable(Level.FINE)) {
                    logger.fine("no default config ID for [" + intercept + "]");
                }
                return null;
            }
        }

        // we found the DD provider ID in the module config
        // or we found a default module config

        // check provider-type
        if (idEntry.getType().indexOf(type) < 0) {
            if (logger != null && logger.isLoggable(Level.FINE)) {
                logger.fine("request type [" + type + "] does not match config type [" + idEntry.getType() + "]");
            }
            return null;
        }

        // check whether a policy is set
        AuthPolicy reqP, respP;
        if (requestPolicy != null || responsePolicy != null) {
            reqP = requestPolicy;
            respP = responsePolicy;
        } else if (idEntry.getRequestPolicy() != null || idEntry.getResponsePolicy() != null) {
            // default
            reqP = new AuthPolicy(idEntry.getRequestPolicy());
            respP = new AuthPolicy(idEntry.getResponsePolicy());
        } else {
            // optimization: if policy was not set, return null
            if (logger != null && logger.isLoggable(Level.FINE)) {
                logger.fine("no policy applies");
            }
            return null;
        }

        // return the configured modules with the correct policies

        // ConfigFile.Entry[] entries = new Entry[idEntry.modules.size()];
        ConfigFile.Entry[] entries = new Entry[1];
        for (int i = 0; i < entries.length; i++) {
            // Login Bridge profile?
            entries[i] = new ConfigFile.Entry(reqP, respP, idEntry.getModuleClassName(),
                    AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, idEntry.getOptions());
        }

        if (logger != null && logger.isLoggable(Level.FINE)) {
            logger.fine("getEntries found " + entries.length + " entries for: " + intercept + " -- " + id);

            for (int i = 0; i < entries.length; i++) {
                logger.fine("Entry " + (i + 1) + ":" + "\n    module class: " + entries[i].getLoginModuleName() + "\n    flag: "
                        + entries[i].getControlFlag() + "\n    options: " + entries[i].getOptions() + "\n    request policy: "
                        + entries[i].requestPolicy + "\n    response policy: " + entries[i].responsePolicy);
            }

        }

        return entries;
    }

    /**
     * get a custom config file parser
     *
     * XXX custom file that can be used in place of [domain|sun-acc].xml
     */
    private static ConfigParser loadParser(String className) throws IOException {
        try {

            final String finalClassName = className;
            final ClassLoader finalLoader = AuthConfig.getClassLoader();

            return (ConfigParser) java.security.AccessController.doPrivileged(new java.security.PrivilegedExceptionAction() {
                @Override
                public Object run() throws Exception {
                    Class c = Class.forName(finalClassName, true, finalLoader);
                    return c.newInstance();
                }
            });
        } catch (java.security.PrivilegedActionException pae) {
            IOException iex = new IOException(pae.getException().toString());
            iex.initCause(pae.getException());
            throw iex;
        }
    }

    /**
     * get the default callback handler
     */
    private static CallbackHandler loadDefaultCallbackHandler() throws AuthException {

        // get the default handler class
        try {

            final ClassLoader finalLoader = AuthConfig.getClassLoader();

            return (CallbackHandler) java.security.AccessController.doPrivileged(new java.security.PrivilegedExceptionAction() {
                @Override
                public Object run() throws Exception {

                    String className = DEFAULT_HANDLER_CLASS;
                    Class c = Class.forName(className, true, finalLoader);
                    return c.newInstance();
                }
            });
        } catch (java.security.PrivilegedActionException pae) {
            AuthException aex = new AuthException(pae.getException().toString());
            aex.initCause(pae.getException());
            throw aex;
        }
    }

    /**
     * Instantiate+initialize module class
     */
    private static Object createModule(ConfigFile.Entry entry, CallbackHandler handler) throws AuthException {
        try {

            // instantiate module using no-arg constructor

            Object newModule = entry.newInstance();

            // initialize module

            Object[] initArgs = { entry.getRequestPolicy(), entry.getResponsePolicy(), handler, entry.getOptions() };

            try {
                Method initMethod = newModule.getClass().getMethod(AuthContext.INIT, AuthPolicy.class, AuthPolicy.class,
                        CallbackHandler.class, Map.class);
                initMethod.invoke(newModule, initArgs);
                // return the new module
                return newModule;
            } catch (Exception ex) {
                throw new SecurityException(
                        "could not invoke " + AuthContext.INIT + " method in module: " + newModule.getClass().getName() + " " + ex, ex);
            }

        } catch (Exception e) {
            if (e instanceof AuthException) {
                throw (AuthException) e;
            }
            AuthException ae = new AuthException();
            ae.initCause(e);
            throw ae;
        }
    }

    /**
     * Class representing a single AuthModule entry configured for an ID, interception point, and stack.
     *
     * 

* An instance of this class contains the same information as its superclass, AppConfigurationEntry. It additionally * stores the request and response policy assigned to this module. * *

* This class also provides a way for a caller to obtain an instance of the module listed in the entry by invoking the * newInstance method. */ static class Entry extends javax.security.auth.login.AppConfigurationEntry { // for loading modules private static final Class[] PARAMS = {}; private static final Object[] ARGS = {}; private AuthPolicy requestPolicy; private AuthPolicy responsePolicy; Object module = null; // convenience location to store instance - // package private for AuthContext /** * Construct a ConfigFile entry. * *

* An entry encapsulates a single module and its related information. * * @param requestPolicy the request policy assigned to the module listed in this entry, which may be null. * * @param responsePolicy the response policy assigned to the module listed in this entry, which may be null. * * @param moduleClass the fully qualified class name of the module. * * @param flag the module control flag. This value must either be REQUIRED, REQUISITE, SUFFICIENT, or OPTIONAL. * * @param options the options configured for this module. */ Entry(AuthPolicy requestPolicy, AuthPolicy responsePolicy, String moduleClass, AppConfigurationEntry.LoginModuleControlFlag flag, Map options) { super(moduleClass, flag, options); this.requestPolicy = requestPolicy; this.responsePolicy = responsePolicy; } /** * Return the request policy assigned to this module. * * @return the policy, which may be null. */ AuthPolicy getRequestPolicy() { return requestPolicy; } /** * Return the response policy assigned to this module. * * @return the policy, which may be null. */ AuthPolicy getResponsePolicy() { return responsePolicy; } /** * Return a new instance of the module contained in this entry. * *

* The default implementation of this method attempts to invoke the default no-args constructor of the module class. * This method may be overridden if a different constructor should be invoked. * * @return a new instance of the module contained in this entry. * * @exception AuthException if the instantiation failed. */ Object newInstance() throws AuthException { try { final ClassLoader finalLoader = AuthConfig.getClassLoader(); String clazz = getLoginModuleName(); Class c = Class.forName(clazz, true, finalLoader); java.lang.reflect.Constructor constructor = c.getConstructor(PARAMS); return constructor.newInstance(ARGS); } catch (Exception e) { AuthException ae = new AuthException(); ae.initCause(e); throw ae; } } } /** * parsed Intercept entry */ /* * static class InterceptEntry { String defaultClientID; String defaultServerID; HashMap idMap; InterceptEntry(String * defaultClientID, String defaultServerID, HashMap idMap) { this.defaultClientID = defaultClientID; * this.defaultServerID = defaultServerID; this.idMap = idMap; } } */ /** * parsed ID entry */ /* * static class IDEntry { private String type; // provider type (client, server, client-server) private AuthPolicy * requestPolicy; private AuthPolicy responsePolicy; private ArrayList modules; IDEntry(String type, AuthPolicy * requestPolicy, AuthPolicy responsePolicy, ArrayList modules) { this.type = type; this.modules = modules; * this.requestPolicy = requestPolicy; this.responsePolicy = responsePolicy; } // XXX delete this later IDEntry(String * type, String requestPolicy, String responsePolicy, ArrayList modules) { this.type = type; if (requestPolicy != null) * { this.requestPolicy = new AuthPolicy(AuthPolicy.SOURCE_AUTH_SENDER, true, // recipient-auth true); // beforeContent * } if (responsePolicy != null) { this.responsePolicy = new AuthPolicy(AuthPolicy.SOURCE_AUTH_CONTENT, true, // * recipient-auth false); // beforeContent } this.modules = modules; } } */ /** * Default implementation of ClientAuthContext. */ private static class ConfigClient implements ClientAuthContext { // class that does all the work private AuthContext context; ConfigClient(Entry[] entries) throws AuthException { context = new AuthContext(entries, logger); } @Override public void secureRequest(AuthParam param, Subject subject, Map sharedState) throws AuthException { // invoke modules Object[] args = { param, subject, sharedState }; context.invoke(AuthContext.SECURE_REQUEST, args); } @Override public void validateResponse(AuthParam param, Subject subject, Map sharedState) throws AuthException { // invoke modules Object[] args = { param, subject, sharedState }; context.invoke(AuthContext.VALIDATE_RESPONSE, args); } @Override public void disposeSubject(Subject subject, Map sharedState) throws AuthException { // invoke modules Object[] args = { subject, sharedState }; context.invoke(AuthContext.DISPOSE_SUBJECT, args); } } /** * Default implementation of ServerAuthContext. */ private static class ConfigServer implements ServerAuthContext { // class that does all the work private AuthContext context; ConfigServer(Entry[] entries) throws AuthException { context = new AuthContext(entries, logger); } @Override public void validateRequest(AuthParam param, Subject subject, Map sharedState) throws AuthException { // invoke modules Object[] args = { param, subject, sharedState }; context.invoke(AuthContext.VALIDATE_REQUEST, args); } @Override public void secureResponse(AuthParam param, Subject subject, Map sharedState) throws AuthException { // invoke modules Object[] args = { param, subject, sharedState }; context.invoke(AuthContext.SECURE_RESPONSE, args); } @Override public void disposeSubject(Subject subject, Map sharedState) throws AuthException { // invoke modules Object[] args = { subject, sharedState }; context.invoke(AuthContext.DISPOSE_SUBJECT, args); } @Override public boolean managesSessions(Map sharedState) throws AuthException { // invoke modules Object[] args = { sharedState }; Object[] rValues = null; try { rValues = context.invoke(AuthContext.MANAGES_SESSIONS, args); } catch (AuthException ae) { // this new method may not be implemeneted // by old modules if (!(ae.getCause() instanceof NoSuchMethodException)) { throw ae; } } boolean rvalue = false; for (int i = 0; rValues != null && i < rValues.length; i++) { if (rValues[i] != null) { boolean thisValue = ((Boolean) rValues[i]).booleanValue(); rvalue = rvalue | thisValue; } } return rvalue; } } private static class DelegatingHandler implements CallbackHandler { CallbackHandler handler; CallbackHandler defaultHandler; private DelegatingHandler(CallbackHandler cbh) { handler = cbh; try { defaultHandler = ConfigFile.loadDefaultCallbackHandler(); } catch (Exception e) { defaultHandler = null; } } @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { if (defaultHandler == null) { handler.handle(callbacks); } else { Callback[] oneCallback = new Callback[1]; for (int i = 0; i < callbacks.length; i++) { boolean tryDefault = false; oneCallback[0] = callbacks[i]; try { handler.handle(oneCallback); } catch (UnsupportedCallbackException uce) { tryDefault = true; } if (tryDefault) { defaultHandler.handle(oneCallback); } } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy