/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.apache.catalina.realm;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.naming.Context;
import org.apache.catalina.Group;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Role;
import org.apache.catalina.User;
import org.apache.catalina.UserDatabase;
import org.apache.catalina.Wrapper;
import org.apache.tomcat.util.ExceptionUtils;
Implementation of Realm
that is based on an implementation of UserDatabase
made available through the global JNDI resources configured for this instance of Catalina. Set the resourceName
parameter to the global JNDI resources name for the
configured instance of UserDatabase
that we should consult.
Author: Craig R. McClanahan Since: 4.1
/**
* Implementation of {@link org.apache.catalina.Realm} that is based on an
* implementation of {@link UserDatabase} made available through the global JNDI
* resources configured for this instance of Catalina. Set the
* <code>resourceName</code> parameter to the global JNDI resources name for the
* configured instance of <code>UserDatabase</code> that we should consult.
*
* @author Craig R. McClanahan
* @since 4.1
*/
public class UserDatabaseRealm extends RealmBase {
// ----------------------------------------------------- Instance Variables
The UserDatabase
we will use to authenticate users and
identify associated roles.
/**
* The <code>UserDatabase</code> we will use to authenticate users and
* identify associated roles.
*/
protected UserDatabase database = null;
The global JNDI name of the UserDatabase
resource we will be
utilizing.
/**
* The global JNDI name of the <code>UserDatabase</code> resource we will be
* utilizing.
*/
protected String resourceName = "UserDatabase";
// ------------------------------------------------------------- Properties
Returns: the global JNDI name of the UserDatabase
resource we
will be using.
/**
* @return the global JNDI name of the <code>UserDatabase</code> resource we
* will be using.
*/
public String getResourceName() {
return resourceName;
}
Set the global JNDI name of the UserDatabase
resource we
will be using.
Params: - resourceName – The new global JNDI name
/**
* Set the global JNDI name of the <code>UserDatabase</code> resource we
* will be using.
*
* @param resourceName The new global JNDI name
*/
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
// --------------------------------------------------------- Public Methods
Return true
if the specified Principal has the specified
security role, within the context of this Realm; otherwise return
false
. This implementation returns true
if the
User
has the role, or if any Group
that the
User
is a member of has the role.
Params: - principal – Principal for whom the role is to be checked
- role – Security role to be checked
/**
* Return <code>true</code> if the specified Principal has the specified
* security role, within the context of this Realm; otherwise return
* <code>false</code>. This implementation returns <code>true</code> if the
* <code>User</code> has the role, or if any <code>Group</code> that the
* <code>User</code> is a member of has the role.
*
* @param principal Principal for whom the role is to be checked
* @param role Security role to be checked
*/
@Override
public boolean hasRole(Wrapper wrapper, Principal principal, String role) {
// Check for a role alias defined in a <security-role-ref> element
if (wrapper != null) {
String realRole = wrapper.findSecurityReference(role);
if (realRole != null)
role = realRole;
}
if (principal instanceof GenericPrincipal) {
GenericPrincipal gp = (GenericPrincipal) principal;
if (gp.getUserPrincipal() instanceof User) {
principal = gp.getUserPrincipal();
}
}
if (!(principal instanceof User)) {
// Play nice with SSO and mixed Realms
// No need to pass the wrapper here because role mapping has been
// performed already a few lines above
return super.hasRole(null, principal, role);
}
if ("*".equals(role)) {
return true;
} else if (role == null) {
return false;
}
User user = (User) principal;
Role dbrole = database.findRole(role);
if (dbrole == null) {
return false;
}
if (user.isInRole(dbrole)) {
return true;
}
Iterator<Group> groups = user.getGroups();
while (groups.hasNext()) {
Group group = groups.next();
if (group.isInRole(dbrole)) {
return true;
}
}
return false;
}
// ------------------------------------------------------ Protected Methods
@Override
public void backgroundProcess() {
database.backgroundProcess();
}
Return the password associated with the given principal's user name.
/**
* Return the password associated with the given principal's user name.
*/
@Override
protected String getPassword(String username) {
User user = database.findUser(username);
if (user == null) {
return null;
}
return user.getPassword();
}
Return the Principal associated with the given user name.
/**
* Return the Principal associated with the given user name.
*/
@Override
protected Principal getPrincipal(String username) {
User user = database.findUser(username);
if (user == null) {
return null;
}
List<String> roles = new ArrayList<>();
Iterator<Role> uroles = user.getRoles();
while (uroles.hasNext()) {
Role role = uroles.next();
roles.add(role.getName());
}
Iterator<Group> groups = user.getGroups();
while (groups.hasNext()) {
Group group = groups.next();
uroles = group.getRoles();
while (uroles.hasNext()) {
Role role = uroles.next();
roles.add(role.getName());
}
}
return new GenericPrincipal(username, user.getPassword(), roles, user);
}
// ------------------------------------------------------ Lifecycle Methods
Prepare for the beginning of active use of the public methods of this component and implement the requirements of LifecycleBase.startInternal()
. Throws: - LifecycleException – if this component detects a fatal error
that prevents this component from being used
/**
* Prepare for the beginning of active use of the public methods of this
* component and implement the requirements of
* {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
*
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
@Override
protected void startInternal() throws LifecycleException {
try {
Context context = getServer().getGlobalNamingContext();
database = (UserDatabase) context.lookup(resourceName);
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
containerLog.error(sm.getString("userDatabaseRealm.lookup", resourceName), e);
database = null;
}
if (database == null) {
throw new LifecycleException(
sm.getString("userDatabaseRealm.noDatabase", resourceName));
}
super.startInternal();
}
Gracefully terminate the active use of the public methods of this component and implement the requirements of LifecycleBase.stopInternal()
. Throws: - LifecycleException – if this component detects a fatal error
that needs to be reported
/**
* Gracefully terminate the active use of the public methods of this
* component and implement the requirements of
* {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
*
* @exception LifecycleException if this component detects a fatal error
* that needs to be reported
*/
@Override
protected void stopInternal() throws LifecycleException {
// Perform normal superclass finalization
super.stopInternal();
// Release reference to our user database
database = null;
}
}