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

com.sun.enterprise.security.auth.realm.Realm 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.enterprise.security.auth.realm;

import com.sun.enterprise.security.SecurityLoggerInfo;
import com.sun.enterprise.security.util.IASSecurityException;
import java.io.*;
import java.util.*;
import com.sun.enterprise.util.*;
import java.lang.ref.WeakReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.external.probe.provider.PluginPoint;
import org.glassfish.external.probe.provider.StatsProviderManager;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.api.ClassLoaderHierarchy;
import org.glassfish.internal.api.Globals;
import org.jvnet.hk2.annotations.Contract;

/**
 * javadoc
 *
 * @see java.security.Principal
 *
 * @author Harish Prabandham
 * @author Harpreet Singh
 * @author Jyri Virkki
 * @author Shing Wai Chan
 *
 */
@Contract
public abstract class Realm implements Comparable {

    private static LocalStringManagerImpl localStrings =
	new LocalStringManagerImpl(Realm.class);

//    private static Hashtable loadedRealms = new Hashtable();
    private String myName;

    // Keep track of name of default realm. This is updated during startup
    // using value from server.xml
//    private static String defaultRealmName="default";
    
    // Keep a mapping from "default" to default realm (if no such named
    // realm is present) for the sake of all the hardcoded accesses to it.
    // This needs to be removed as part of RI security service cleanup.
    final static String RI_DEFAULT="default";

    // All realms have a set of properties from config file, consolidate.
    private Properties ctxProps;

    // for assign-groups
    private static final String PARAM_GROUPS = "assign-groups";
    private static final String GROUPS_SEP = ",";
    private List assignGroups = null;
    public static final String PARAM_GROUP_MAPPING="group-mapping";
    protected GroupMapper groupMapper = null;
    private static RealmStatsProvider realmStatsProvier = null;
    private static final String DEFAULT_DIGEST_ALGORITHM = "default-digest-algorithm";
    private static final String DEFAULT_DEF_DIG_ALGO_VAL = "SHA-256";

    private static WeakReference realmsManager = new WeakReference(null);
    private String defaultDigestAlgorithm = null;

    protected static final Logger _logger = SecurityLoggerInfo.getLogger();

    
    /**
     * Returns the name of this realm.
     *
     * @return realm name.
     */
    public final String	getName() { 
	return myName; 
    }

    protected String getDefaultDigestAlgorithm() {
        return defaultDigestAlgorithm;
    }

    
    /**
     * Assigns the name of this realm, and stores it in the cache
     * of realms.  Used when initializing a newly created in-memory
     * realm object; if the realm already has a name, there is no
     * effect.
     *
     * @param name name to be assigned to this realm.
     */
    protected final void setName(String name) {
	if (myName != null) {
	    return;
	}
	myName = name;
    }

    
    /**
     * Returns the name of this realm.
     *
     * @return name of realm.
     */
    @Override
    public String  toString() { 
	return myName; 
    }

    
    /**
     * Compares a realm to another.  The comparison first considers the
     * authentication type, so that realms supporting the same kind of
     * user authentication are grouped together.  Then it compares realm
     * realm names.  Realms compare "before" other kinds of objects (i.e.
     * there's only a partial order defined, in the case that those other
     * objects compare themselves "before" a realm object).
     */
    public int compareTo (Object realm) {
	if (!(realm instanceof Realm)) {
	    return 1;
	}
	
	Realm 	r = (Realm) realm;
	String	str = r.getAuthType ();
	int	temp;
	
	if ((temp = getAuthType ().compareTo (str)) != 0) {
	    return temp;
	}

	str = r.getName ();
	return getName ().compareTo (str);
    }


    /**
     * Instantiate a Realm with the given name and properties using the
     * Class name given. This method is used by iAS and not RI.
     *
     * @param name Name of the new realm.
     * @param className Java Class name of the realm to create.
     * @param props Properties containing values of the Property element
     *     from server.xml
     * @returns Reference to the new Realm. The Realm class keeps an internal
     *     list of all instantiated realms.
     * @throws BadRealmException If the requested realm cannot be instantiated.
     *
     */
    public static synchronized Realm instantiate(String name, String className,
                                    Properties props)
        throws BadRealmException
    {
        //Register the realm provider
        registerRealmStatsProvier();
        
        Realm realmClass = _getInstance(name);
        if(realmClass == null) {
            realmClass = doInstantiate(name, className, props);
            RealmsManager mgr = getRealmsManager();
            mgr.putIntoLoadedRealms(name, realmClass);
        }
        return realmClass;
    }

    /**
     * Instantiate a Realm with the given name and properties using the
     * Class name given. This method is used by iAS and not RI.
     *
     * @param name Name of the new realm.
     * @param className Java Class name of the realm to create.
     * @param props Properties containing values of the Property element
     *     from server.xml
     * @param configName the config to which this realm belongs
     * @returns Reference to the new Realm. The Realm class keeps an internal
     *     list of all instantiated realms.
     * @throws BadRealmException If the requested realm cannot be instantiated.
     *
     */
    public static synchronized Realm instantiate(String name, String className,
                                    Properties props, String configName)
        throws BadRealmException
    {
        //Register the realm provider
        registerRealmStatsProvier();

        Realm realmClass = _getInstance(configName, name);
        if(realmClass == null) {
            realmClass = doInstantiate(name, className, props);
            RealmsManager mgr = getRealmsManager();
            mgr.putIntoLoadedRealms(configName, name, realmClass);
        }
        return realmClass;

    }

    private static void registerRealmStatsProvier() {
        if (realmStatsProvier == null) {
            getRealmStatsProvier();
            StatsProviderManager.register("security", PluginPoint.SERVER, "security/realm", realmStatsProvier);
        }
    }

    public static synchronized void getRealmStatsProvier(){
        if(realmStatsProvier == null){
            realmStatsProvier = new RealmStatsProvider();
        }
    }

    /**
     * Instantiate a Realm with the given name, loading properties from
     * the given file. This method is only used by RI and is not called
     * anywhere in iAS.
     * Note : this method stands unused in V3.1 but keeping it since it is a 
     * public method.
     * @deprecated
     * @param realmName Name of the new realm.
     * @param f File containing Properties for the new realm.
     */
    public static synchronized Realm instantiate(String realmName, File f)
    throws NoSuchRealmException, BadRealmException, FileNotFoundException
    {


        if (!f.exists() || !f.isFile()) {
            throw new FileNotFoundException ();
        }
        
        if(_getInstance(realmName) != null) {
            throw new BadRealmException(
                localStrings.getLocalString("realm.already_exists", 
                                            "This Realm already exists."));
        } 
        
        //
        // First load the description from properties.
        //
        InputStream in = null;
        Properties  props = new Properties();
        
        try{    
            in = new FileInputStream(f);
            props.load(in);
            //
            // Then instantiate and initialize, using the single mandatory
            // property ("classname").
            //
            String classname = props.getProperty("classname");
            assert (classname != null);

            return doInstantiate(realmName, classname, props);
        } catch (IOException e) {
            throw new BadRealmException(e.toString());
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch(Exception ex) {
                }
            }
        }
    }

    
    /**
     * Instantiates a Realm class of the given type and invokes its init()
     *
     */
    private static synchronized Realm doInstantiate(String name, String className,
                                       Properties props)
        throws BadRealmException
    {
        
        ServiceLocator habitat = Globals.getDefaultHabitat();
        RealmsManager mgr = null;
        try {
            mgr = getRealmsManager();
            Class realmClass = null;
            //try a HK2 route first
            Realm r = habitat.getService(Realm.class, name);
            if (r == null) {
                try {
                    //TODO: workaround here. Once fixed in V3 we should be able to use
                    //Context ClassLoader instead.
                    ClassLoaderHierarchy hierarchy =
                            habitat.getService(ClassLoaderHierarchy.class);
                    realmClass = hierarchy.getCommonClassLoader().loadClass(className);
                    Object obj = realmClass.newInstance();
                    r = (Realm) obj;
                } catch (ClassNotFoundException ex) {
                    realmClass = Class.forName(className);
                    Object obj = realmClass.newInstance();
                    r = (Realm) obj;
                }
            }

            r.setName(name);
            r.init(props);
            if (mgr == null) {
                throw new BadRealmException("Unable to locate RealmsManager Service");
            }
            _logger.log(Level.INFO, SecurityLoggerInfo.realmCreated ,new Object[]{name, className});
            return r;


        } catch (NoSuchRealmException ex) {
            throw new BadRealmException(ex);
        } catch (InstantiationException ex) {
            throw new BadRealmException(ex);
        } catch (IllegalAccessException ex) {
            throw new BadRealmException(ex);
        } catch (ClassNotFoundException ex) {
            throw new BadRealmException(ex);
        }
    }


    /**
     * Replace a Realm instance. Can be used by a Realm subclass to
     * replace a previously initialized instance of itself. Future
     * getInstance requests will then obtain the new instance.
     *
     * 

Minimal error checking is done. The realm being replaced must * already exist (instantiate() was previously called), the new * instance must be fully initialized properly and it must of course * be of the same class as the previous instance. * * @param realm The new realm instance. * @param name The (previously instantiated) name for this realm. * */ protected static synchronized void updateInstance(Realm realm, String name) { RealmsManager mgr = getRealmsManager(); if (mgr == null) { throw new RuntimeException("Unable to locate RealmsManager Service"); } Realm oldRealm = mgr.getFromLoadedRealms(name); if (!oldRealm.getClass().equals(realm.getClass())) { // would never happen unless bug in realm subclass throw new Error("Incompatible class "+realm.getClass()+ " in replacement realm "+name); } realm.setName(oldRealm.getName()); mgr.putIntoLoadedRealms(name, realm); _logger.log(Level.INFO, SecurityLoggerInfo.realmUpdated, new Object[]{realm.getName()}); } /** * Replace a Realm instance. Can be used by a Realm subclass to * replace a previously initialized instance of itself. Future * getInstance requests will then obtain the new instance. * *

Minimal error checking is done. The realm being replaced must * already exist (instantiate() was previously called), the new * instance must be fully initialized properly and it must of course * be of the same class as the previous instance. * * @param realm The new realm instance. * @param name The (previously instantiated) name for this realm. * */ protected static synchronized void updateInstance(String configName, Realm realm, String name) { RealmsManager mgr = getRealmsManager(); if (mgr == null) { throw new RuntimeException("Unable to locate RealmsManager Service"); } Realm oldRealm = mgr.getFromLoadedRealms(configName, name); if (!oldRealm.getClass().equals(realm.getClass())) { // would never happen unless bug in realm subclass throw new Error("Incompatible class " + realm.getClass() + " in replacement realm " + name); } realm.setName(oldRealm.getName()); mgr.putIntoLoadedRealms(configName, name, realm); _logger.log(Level.INFO, SecurityLoggerInfo.realmUpdated, new Object[]{realm.getName()}); } /** * Convenience method which returns the Realm object representing * the current default realm. Equivalent to * getInstance(getDefaultRealm()). * * @return Realm representing default realm. * @exception NoSuchRealmException if default realm does not exist */ public static synchronized Realm getDefaultInstance() throws NoSuchRealmException { return getInstance(getDefaultRealm()); } /** * Returns the name of the default realm. * * @return Default realm name. * */ public static synchronized String getDefaultRealm() { RealmsManager mgr = getRealmsManager(); if (mgr != null) { return mgr.getDefaultRealmName(); } else { throw new RuntimeException("Unable to locate RealmsManager Service"); } } /** * Sets the name of the default realm. * * @param realmName Name of realm to set as default. * */ public static synchronized void setDefaultRealm(String realmName) { //defaultRealmName = realmName; RealmsManager mgr = getRealmsManager(); if (mgr != null) { mgr.setDefaultRealmName(realmName); } else { throw new RuntimeException("Unable to locate RealmsManager Service"); } } /** * Remove realm with given name from cache. * @param realmName * @exception NoSuchRealmException */ public static synchronized void unloadInstance(String realmName) throws NoSuchRealmException { //make sure instance exist getInstance(realmName); RealmsManager mgr = getRealmsManager(); if (mgr != null) { mgr.removeFromLoadedRealms(realmName); } else { throw new RuntimeException("Unable to locate RealmsManager Service"); } _logger.log(Level.INFO, SecurityLoggerInfo.realmDeleted, realmName); } /** * Remove realm with given name from cache. * @param realmName * @exception NoSuchRealmException */ public static synchronized void unloadInstance(String configName, String realmName) throws NoSuchRealmException { //make sure instance exist //getInstance(configName, realmName); RealmsManager mgr = getRealmsManager(); if (mgr != null) { mgr.removeFromLoadedRealms(configName, realmName); } else { throw new RuntimeException("Unable to locate RealmsManager Service"); } _logger.log(Level.INFO, SecurityLoggerInfo.realmDeleted, realmName); } /** * Set a realm property. * * @param name property name. * @param value property value. * */ public synchronized void setProperty(String name, String value) { ctxProps.setProperty(name, value); } /** * Get a realm property. * * @param name property name. * @returns value. * */ public synchronized String getProperty(String name) { return ctxProps.getProperty(name); } /** * Return properties of the realm. */ protected synchronized Properties getProperties() { return ctxProps; } /** * Returns name of JAAS context used by this realm. * *

The JAAS context is defined in server.xml auth-realm element * associated with this realm. * * @return String containing JAAS context name. * */ public synchronized String getJAASContext() { return ctxProps.getProperty(IASRealm.JAAS_CONTEXT_PARAM); } /** * Returns the realm identified by the name which is passed * as a parameter. This function knows about all the realms * which exist; it is not possible to store (or create) one * which is not accessible through this routine. * * @param name identifies the realm * @return the requested realm * @exception NoSuchRealmException if the realm is invalid * @exception BadRealmException if realm data structures are bad */ public static synchronized Realm getInstance(String name) throws NoSuchRealmException { Realm retval = _getInstance(name); if (retval == null) { throw new NoSuchRealmException( localStrings.getLocalString("realm.no_such_realm", name + " realm does not exist.", new Object[] { name })); } return retval; } /** * Returns the realm identified by the name which is passed * as a parameter. This function knows about all the realms * which exist; it is not possible to store (or create) one * which is not accessible through this routine. * * @param name identifies the realm * @return the requested realm * @exception NoSuchRealmException if the realm is invalid * @exception BadRealmException if realm data structures are bad */ public static synchronized Realm getInstance(String configName, String name) throws NoSuchRealmException { Realm retval = _getInstance(configName, name); if (retval == null) { throw new NoSuchRealmException( localStrings.getLocalString("realm.no_such_realm", name + " realm does not exist.", new Object[] { name })); } return retval; } /** * This is a private method for getting realm instance. * If realm does not exist, then it will not return null rather than * throw exception. * @param name identifies the realm * @return the requested realm */ private static synchronized Realm _getInstance(String name) { RealmsManager mgr = getRealmsManager(); if (mgr != null) { return mgr._getInstance(name); } else { throw new RuntimeException("Unable to locate RealmsManager Service"); } } /** * This is a private method for getting realm instance. * If realm does not exist, then it will not return null rather than * throw exception. * @param name identifies the realm * @return the requested realm */ private static synchronized Realm _getInstance(String configName, String name) { RealmsManager mgr = getRealmsManager(); if (mgr != null) { return mgr._getInstance(configName, name); } else { throw new RuntimeException("Unable to locate RealmsManager Service"); } } /** * Returns the names of accessible realms. * @return set of realm names */ public static synchronized Enumeration getRealmNames() { RealmsManager mgr = getRealmsManager(); if (mgr != null) { return mgr.getRealmNames(); } throw new RuntimeException("Unable to locate RealmsManager Service"); } /** * The default constructor creates a realm which will later * be initialized, either from properties or by deserializing. */ protected Realm() { ctxProps = new Properties(); } /** * Initialize a realm with some properties. This can be used * when instantiating realms from their descriptions. This * method may only be called a single time. * * @param props initialization parameters used by this realm. * @exception BadRealmException if the configuration parameters * identify a corrupt realm * @exception NoSuchRealmException if the configuration parameters * specify a realm which doesn't exist */ protected void init(Properties props) throws BadRealmException, NoSuchRealmException { String groupList = props.getProperty(PARAM_GROUPS); if (groupList != null && groupList.length() > 0) { this.setProperty(PARAM_GROUPS, groupList); assignGroups = new ArrayList(); StringTokenizer st = new StringTokenizer(groupList, GROUPS_SEP); while (st.hasMoreTokens()) { String grp = (String)st.nextToken(); if (!assignGroups.contains(grp)) { assignGroups.add(grp); } } } String groupMapping = props.getProperty(PARAM_GROUP_MAPPING); if (groupMapping != null) { groupMapper = new GroupMapper(); groupMapper.parse(groupMapping); } String defaultDigestAlgo = null; if(_getRealmsManager() != null) { defaultDigestAlgo = _getRealmsManager().getDefaultDigestAlgorithm(); } this.defaultDigestAlgorithm = (defaultDigestAlgo == null)?DEFAULT_DEF_DIG_ALGO_VAL:defaultDigestAlgo; } private static synchronized RealmsManager _getRealmsManager() { if (realmsManager.get() == null) { if(Globals.getDefaultHabitat() != null) { realmsManager = new WeakReference(Globals.get(RealmsManager.class)); } else { return null; } } return realmsManager.get(); } private static RealmsManager getRealmsManager() { if (realmsManager.get() != null) { return realmsManager.get(); } return _getRealmsManager(); } /** * Checks if the given realm name is loaded/valid. * @param String name of the realm to check. * @return true if realm present, false otherwise. */ public static boolean isValidRealm(String name) { RealmsManager mgr = getRealmsManager(); if (mgr != null) { return mgr.isValidRealm(name); } throw new RuntimeException("Unable to locate RealmsManager Service"); } /** * Checks if the given realm name is loaded/valid. * @param String name of the realm to check. * @return true if realm present, false otherwise. */ public static boolean isValidRealm(String configName, String name) { RealmsManager mgr = getRealmsManager(); if (mgr != null) { return mgr.isValidRealm(configName, name); } throw new RuntimeException("Unable to locate RealmsManager Service"); } /** * Add assign groups to given Vector of groups. * To be used by getGroupNames. * @param grps */ protected String[] addAssignGroups(String[] grps) { String[] resultGroups = grps; if (assignGroups != null && assignGroups.size() > 0) { List groupList = new ArrayList(); if (grps != null && grps.length > 0) { for (String grp : grps) { groupList.add(grp); } } for (String agrp : assignGroups) { if (!groupList.contains(agrp)) { groupList.add(agrp); } } resultGroups = groupList.toArray(new String[groupList.size()]); } return resultGroups; } protected ArrayList getMappedGroupNames(String group) { if (groupMapper != null) { ArrayList result = new ArrayList(); groupMapper.getMappedGroups(group, result); return result; } return null; } //---[ Abstract methods ]------------------------------------------------ /** * Returns a short (preferably less than fifteen characters) description * of the kind of authentication which is supported by this realm. * * @return description of the kind of authentication that is directly * supported by this realm. */ public abstract String getAuthType (); /** * Returns an AuthenticationHandler object which can be used to * authenticate within this realm. * * @return An AuthenticationHandler object for this realm. */ public abstract AuthenticationHandler getAuthenticationHandler (); /** * Returns names of all the users in this particular realm. * * @return enumeration of user names (strings) * @exception BadRealmException if realm data structures are bad */ public abstract Enumeration getUserNames() throws BadRealmException; /** * Returns the information recorded about a particular named user. * * @param name name of the user whose information is desired * @return the user object * @exception NoSuchUserException if the user doesn't exist * @exception BadRealmException if realm data structures are bad */ public abstract User getUser(String name) throws NoSuchUserException, BadRealmException; /** * Returns names of all the groups in this particular realm. * * @return enumeration of group names (strings) * @exception BadRealmException if realm data structures are bad */ public abstract Enumeration getGroupNames() throws BadRealmException; /** * Returns the name of all the groups that this user belongs to * @param username name of the user in this realm whose group listing * is needed. * @return enumeration of group names (strings) * @exception InvalidOperationException thrown if the realm does not * support this operation - e.g. Certificate realm does not support this * operation */ public abstract Enumeration getGroupNames (String username) throws InvalidOperationException, NoSuchUserException; /** * Refreshes the realm data so that new users/groups are visible. * * @exception BadRealmException if realm data structures are bad */ public abstract void refresh() throws BadRealmException; /** * Refreshes the realm data so that new users/groups are visible. * * @exception BadRealmException if realm data structures are bad */ public void refresh(String configName) throws BadRealmException { //do nothing } /** * Adds new user to file realm. User cannot exist already. * * @param name User name. * @param password Cleartext password for the user. * @param groupList List of groups to which user belongs. * @throws BadRealmException If there are problems adding user. * */ public abstract void addUser(String name, char[] password, String[] groupList) throws BadRealmException, IASSecurityException; /** * Remove user from file realm. User must exist. * * @param name User name. * @throws NoSuchUserException If user does not exist. * */ public abstract void removeUser(String name) throws NoSuchUserException, BadRealmException; /** * Update data for an existing user. User must exist. * * @param name Current name of the user to update. * @param newName New name to give this user. It can be the same as * the original name. Otherwise it must be a new user name which * does not already exist as a user. * @param password Cleartext password for the user. If non-null the user * password is changed to this value. If null, the original password * is retained. * @param groupList List of groups to which user belongs. * @throws BadRealmException If there are problems adding user. * @throws NoSuchUserException If user does not exist. * */ public abstract void updateUser(String name, String newName, char[] password, String[] groups) throws NoSuchUserException, BadRealmException, IASSecurityException; /** * @return true if the realm implementation support User Management (add,remove,update user) */ public abstract boolean supportsUserManagement(); /** * Persist the realm data to permanent storage * @throws com.sun.enterprise.security.auth.realm.BadRealmException */ public abstract void persist() throws BadRealmException; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy