com.sun.enterprise.security.auth.realm.Realm Maven / Gradle / Ivy
Show all versions of payara-embedded-all Show documentation
/*
* 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;
}