org.jasig.portal.security.provider.ChainingSecurityContext.java Source code

Java tutorial

Introduction

Here is the source code for org.jasig.portal.security.provider.ChainingSecurityContext.java

Source

/**
 * Licensed to Jasig under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Jasig 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.jasig.portal.security.provider;

import java.io.Serializable;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Vector;

import org.jasig.portal.properties.PropertiesManager;
import org.jasig.portal.security.IAdditionalDescriptor;
import org.jasig.portal.security.IOpaqueCredentials;
import org.jasig.portal.security.IParentAwareSecurityContext;
import org.jasig.portal.security.IPrincipal;
import org.jasig.portal.security.ISecurityContext;
import org.jasig.portal.security.PortalSecurityException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * <p>This is the basic abstract class for all security contexts that should
 * chain to children security contexts.</p>
 *
 * @author Andrew Newman, newman@yale.edu
 * @version $Revision$
 * @author Don Fracapane (df7@columbia.edu)
 * Added a new method named getSubContextNames() that returns an Enumeration of names
 * for the subcontexts.
 */
public abstract class ChainingSecurityContext implements ISecurityContext {
    protected final Log log = LogFactory.getLog(getClass());

    /**
     * Default value for stopWhenAuthenticated.
     * This value will be used when the corresponding property cannot be loaded.
     */
    private static final boolean DEFAULT_STOP_WHEN_AUTHENTICATED = true;
    protected static boolean stopWhenAuthenticated = PropertiesManager.getPropertyAsBoolean(
            "org.jasig.portal.security.provider.ChainingSecurityContext.stopWhenAuthenticated",
            DEFAULT_STOP_WHEN_AUTHENTICATED);

    protected boolean isauth = false;
    protected Vector mySubContexts;
    protected ChainingPrincipal myPrincipal;
    protected ChainingOpaqueCredentials myOpaqueCredentials;
    protected IAdditionalDescriptor myAdditionalDescriptor;
    protected Comparator myOrder;

    public ChainingSecurityContext() {
        myPrincipal = new ChainingPrincipal();
        myOpaqueCredentials = new ChainingOpaqueCredentials();
        myAdditionalDescriptor = new ChainingAdditionalDescriptor();
        mySubContexts = new Vector();
    }

    public IPrincipal getPrincipalInstance() {
        if (this.isauth)
            return new ChainingPrincipal();
        else
            return this.myPrincipal;
    }

    public IOpaqueCredentials getOpaqueCredentialsInstance() {
        if (this.isauth)
            return new ChainingOpaqueCredentials();
        else
            return this.myOpaqueCredentials;
    }

    /**
     * We walk the chain of subcontext assigning principals and opaquecredentials
     * from the parent. Note that the contexts themselves should resist
     * actually performing the assignment if an assignment has already been made
     * to either the credentials or the UID.
     */

    public synchronized void authenticate() throws PortalSecurityException {
        int i;
        Enumeration e = mySubContexts.elements();
        boolean error = false;

        while (e.hasMoreElements()) {
            ISecurityContext sctx = ((Entry) e.nextElement()).getCtx();
            // The principal and credential are now set for all subcontexts in Authentication
            try {
                if (sctx instanceof IParentAwareSecurityContext) {
                    ((IParentAwareSecurityContext) sctx).authenticate(this);
                } else {
                    sctx.authenticate();
                }
            } catch (Exception ex) {
                error = true;
                log.error("Exception authenticating subcontext " + sctx, ex);
            }
            // Stop attempting to authenticate if authenticated and if the property flag is set
            if (stopWhenAuthenticated && sctx.isAuthenticated()) {
                break;
            }
        }

        // Zero out the actual credentials if it isn't already null
        if (this.myOpaqueCredentials.credentialstring != null) {
            for (i = 0; i < this.myOpaqueCredentials.credentialstring.length; i++)
                this.myOpaqueCredentials.credentialstring[i] = 0;
            myOpaqueCredentials.credentialstring = null;
        }
        if (error && !this.isauth)
            throw new PortalSecurityException("One of the security subcontexts threw an exception");
        return;
    }

    public IPrincipal getPrincipal() {
        if (this.isauth)
            return this.myPrincipal;
        else
            return null;
    }

    public IOpaqueCredentials getOpaqueCredentials() {
        if (this.isauth)
            return this.myOpaqueCredentials;
        else
            return null;
    }

    public IAdditionalDescriptor getAdditionalDescriptor() {
        if (this.isauth)
            return this.myAdditionalDescriptor;
        else
            return null;
    }

    public boolean isAuthenticated() {
        return this.isauth;
    }

    public synchronized ISecurityContext getSubContext(String name) {
        for (int i = 0; i < mySubContexts.size(); i++) {
            Entry entry = (Entry) mySubContexts.get(i);
            if (entry.getKey() != null && entry.getKey().equals(name)) {
                return (entry.getCtx());
            }
        }
        PortalSecurityException ep = new PortalSecurityException("No such subcontext: " + name);
        if (log.isDebugEnabled())
            log.debug("No such subcontext as " + name, ep);
        return (null);
    }

    public synchronized boolean doesSubContextExist(String name) {
        for (int i = 0; i < mySubContexts.size(); i++) {
            Entry entry = (Entry) mySubContexts.get(i);
            if (entry.getKey() != null && entry.getKey().equals(name)) {
                return (true);
            }
        }
        return (false);
    }

    // Return an enumeration of subcontexts by running the vector and
    // creating the enumeration.  All this so the subcontexts will
    // be returned in the order they appeared in the properties file.
    public synchronized Enumeration getSubContexts() {
        Enumeration e = mySubContexts.elements();
        class Adapter implements Enumeration {
            Enumeration base;

            public Adapter(Enumeration e) {
                this.base = e;
            }

            public boolean hasMoreElements() {
                return base.hasMoreElements();
            }

            public Object nextElement() {
                return ((Entry) base.nextElement()).getCtx();
            }
        }
        return new Adapter(e);
    }

    public synchronized void addSubContext(String name, ISecurityContext ctx) throws PortalSecurityException {
        // Make sure the subcontext does not already exist in the chain
        if (doesSubContextExist(name)) {
            PortalSecurityException ep = new PortalSecurityException("Subcontext already exists: " + name);
            log.error("Subcontext already exists:" + name, ep);
            throw (ep);
        } else {
            mySubContexts.add(new Entry(name, ctx));
        }
    }

    // I 'spose the public class could just implement all of these interfaces
    // but I prefer member classes. -ADN

    protected class ChainingPrincipal implements IPrincipal {
        protected String globalUID;
        protected String UID;
        protected String FullName;

        /**
         * Original, no-arg constructor used by the <code>ChainingSecurityContext</code>.
         *
         */
        public ChainingPrincipal() {
        }

        /**
         * Creates a new <code>ChainingPrincipal</code> from the specified <code>IPrincipal</code>.
         *
         */
        public ChainingPrincipal(IPrincipal p) {
            this.globalUID = p.getGlobalUID();
            this.UID = p.getUID();
            this.FullName = p.getFullName();
        }

        public String getUID() {
            return this.UID;
        }

        public String getGlobalUID() {
            return this.globalUID;
        }

        // This is supposed to be the person's "human readable" name. We should
        // probably do an account lookup at the very least to return this.

        public String getFullName() {
            return this.FullName;
        }

        public void setUID(String UID) {
            if (this.UID == null)
                this.UID = UID;
        }

        public void setFullName(String FullName) {
            if (this.FullName == null)
                this.FullName = FullName;
        }

    }

    protected class ChainingOpaqueCredentials implements IOpaqueCredentials {

        public byte[] credentialstring;

        // Since we want to explicitly zero our credentials after authenticate,
        // copy the credentials here in case a sub-authenticator doesn't want
        // to perform the operation immediately.

        public void setCredentials(byte[] credentials) {
            int i;

            if (this.credentialstring == null) {
                this.credentialstring = new byte[credentials.length];
                for (i = 0; i < credentials.length; i++)
                    this.credentialstring[i] = credentials[i];
            }
        }

        public void setCredentials(String credentials) {
            if (this.credentialstring == null && credentials != null)
                setCredentials(credentials.getBytes());
        }
    }

    // Returns an Enumeration of the names of the subcontexts.
    public synchronized Enumeration getSubContextNames() {
        Vector scNames = new Vector();
        for (int i = 0; i < mySubContexts.size(); i++) {
            Entry entry = (Entry) mySubContexts.get(i);
            if (entry.getKey() != null) {
                scNames.add(entry.getKey());
            }
        }
        return scNames.elements();
    }

    /**
     * A default, placeholder implementation of IAdditionalDescriptor an instance of which
     * is the default value for the instance variable "myAdditionalDescriptor" of instances of
     * this class.
     */
    public class ChainingAdditionalDescriptor implements IAdditionalDescriptor {
        // do nothing
    }

    // entries in our subcontext list
    private static class Entry implements Serializable {
        String key;
        ISecurityContext ctx;

        public Entry(String key, ISecurityContext ctx) {
            this.key = key;
            this.ctx = ctx;
        }

        public ISecurityContext getCtx() {
            return this.ctx;
        }

        public String getKey() {
            return this.key;
        }
    }
}