com.sun.enterprise.security.auth.realm.Realm Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. 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.html
* or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [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.util.IASSecurityException;
import java.io.*;
import java.util.*;
import com.sun.enterprise.util.*;
import org.glassfish.internal.api.ClassLoaderHierarchy;
import org.glassfish.internal.api.Globals;
import org.jvnet.hk2.annotations.Contract;
import org.jvnet.hk2.component.Habitat;
/**
* 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;
/**
* Returns the name of this realm.
*
* @return realm name.
*/
public final String getName() {
return myName;
}
/**
* 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.
*/
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 Realm instantiate(String name, String className,
Properties props)
throws BadRealmException
{
return doInstantiate(name, className, props);
}
/**
* 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.
*
* @param realmName Name of the new realm.
* @param f File containing Properties for the new realm.
*/
public static 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 Realm doInstantiate(String name, String className,
Properties props)
throws BadRealmException
{
Habitat habitat = Globals.getDefaultHabitat();
RealmsManager mgr = null;
try {
mgr = habitat.getComponent(RealmsManager.class);
Class realmClass = null;
//try a HK2 route first
Realm r = habitat.getComponent(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.getComponent(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;
}
}
if (r != null) {
r.setName(name);
r.init(props);
if (mgr == null) {
throw new BadRealmException("Unable to locate RealmsManager Service");
}
mgr.putIntoLoadedRealms(name, r);
return r;
} else {
throw new BadRealmException("Unable to locate Realm class " + className);
}
} 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 void updateInstance(Realm realm, String name)
{
Habitat habitat = Globals.getDefaultHabitat();
RealmsManager mgr = habitat.getComponent(RealmsManager.class);
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);
}
/**
* 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 Realm getDefaultInstance() throws NoSuchRealmException
{
return getInstance(getDefaultRealm());
}
/**
* Returns the name of the default realm.
*
* @return Default realm name.
*
*/
public static String getDefaultRealm() {
Habitat habitat = Globals.getDefaultHabitat();
RealmsManager mgr = habitat.getComponent(RealmsManager.class);
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 void setDefaultRealm(String realmName) {
//defaultRealmName = realmName;
Habitat habitat = Globals.getDefaultHabitat();
RealmsManager mgr = habitat.getComponent(RealmsManager.class);
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 void unloadInstance(String realmName) throws NoSuchRealmException {
//make sure instance exist
getInstance(realmName);
Habitat habitat = Globals.getDefaultHabitat();
RealmsManager mgr = habitat.getComponent(RealmsManager.class);
if (mgr != null) {
mgr.removeFromLoadedRealms(realmName);
} else {
throw new RuntimeException("Unable to locate RealmsManager Service");
}
}
/**
* Set a realm property.
*
* @param name property name.
* @param value property value.
*
*/
public void setProperty(String name, String value)
{
ctxProps.setProperty(name, value);
}
/**
* Get a realm property.
*
* @param name property name.
* @returns value.
*
*/
public String getProperty(String name)
{
return ctxProps.getProperty(name);
}
/**
* Return properties of the realm.
*/
protected 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 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 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;
}
/**
* 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 Realm _getInstance(String name) {
Habitat habitat = Globals.getDefaultHabitat();
RealmsManager mgr = habitat.getComponent(RealmsManager.class);
if (mgr != null) {
return mgr._getInstance(name);
} else {
throw new RuntimeException("Unable to locate RealmsManager Service");
}
}
/**
* Returns the names of accessible realms.
* @return set of realm names
*/
public static Enumeration getRealmNames() {
Habitat habitat = Globals.getDefaultHabitat();
RealmsManager mgr = habitat.getComponent(RealmsManager.class);
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);
}
}
}
}
/**
* 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) {
Habitat habitat = Globals.getDefaultHabitat();
RealmsManager mgr = habitat.getComponent(RealmsManager.class);
if (mgr != null) {
return mgr.isValidRealm(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;
}
//---[ 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;
/**
* 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, String 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, String 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;
}