| /* |
| * Copyright 2005-2008 Jeremy Haile, Les Hazlewood |
| * |
| * Licensed 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.jsecurity.authc; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.jsecurity.subject.PrincipalCollection; |
| import org.jsecurity.subject.SimplePrincipalCollection; |
| |
| import java.io.Serializable; |
| import java.util.Collection; |
| import java.util.HashSet; |
| |
| /** |
| * Simple implementation of the {@link org.jsecurity.authc.Account} interface that |
| * contains principal and credential information as instance variables and exposes them |
| * via getters and setters using standard JavaBean notation. |
| * |
| * <p>Realm implementations can use this for simple principal/credential accounts, but note: |
| * |
| * <p>This class cannot perform its own authorization checks for roles and permissions. It is therefore not sufficient |
| * to use to back a Realm's {@link org.jsecurity.authz.Authorizer Authorizer} method implementations. If you need |
| * an Account object to perform role and permission checks itself, you might want to use instaces of |
| * {@link org.jsecurity.authz.SimpleAuthorizingAccount SimpleAuthorizingAccount} instead of this class. |
| * |
| * <p>But note that a <tt>SimpleAuthorizingAccount</tt> object caches its roles and permission definitions and will not |
| * persist any changes to these definitions back to the source Realm. If you need dynamic runtime modification of Roles |
| * and/or Permissions for any given account, your Realm implementation will need to perform the authorization checks |
| * directly since instances of this class are primarily used for caching and could represent stale data. |
| * |
| * @author Jeremy Haile |
| * @author Les Hazlewood |
| * @see org.jsecurity.authz.SimpleAuthorizingAccount |
| * @since 0.1 |
| */ |
| public class SimpleAccount implements Account, Serializable { |
| |
| /*-------------------------------------------- |
| | C O N S T A N T S | |
| ============================================*/ |
| protected transient final Log logger = LogFactory.getLog(getClass()); |
| |
| /*-------------------------------------------- |
| | I N S T A N C E V A R I A B L E S | |
| ============================================*/ |
| /** |
| * The principals that apply to the authenticated Subject/user. |
| */ |
| private PrincipalCollection principals = null; |
| |
| /** |
| * Credentials that were used to authenticate the user. |
| */ |
| private Object credentials = null; |
| |
| /** |
| * True if the account is locked, false otherwise. |
| */ |
| private boolean locked = false; |
| |
| /** |
| * True if the user's credentials are expired, false otherwise. |
| */ |
| private boolean credentialsExpired = false; |
| |
| /*-------------------------------------------- |
| | C O N S T R U C T O R S | |
| ============================================*/ |
| public SimpleAccount() { |
| } |
| |
| public SimpleAccount( Object principal, Object credentials, String realmName ) { |
| this( principal instanceof PrincipalCollection ? (PrincipalCollection)principal : new SimplePrincipalCollection(realmName, principal), credentials ); |
| } |
| |
| public SimpleAccount( Collection principals, Object credentials, String realmName ) { |
| this( new SimplePrincipalCollection( realmName, principals ), credentials ); |
| } |
| |
| public SimpleAccount( PrincipalCollection principals, Object credentials ) { |
| this.principals = principals; |
| this.credentials = credentials; |
| } |
| |
| /*-------------------------------------------- |
| | A C C E S S O R S / M O D I F I E R S | |
| ============================================*/ |
| |
| public PrincipalCollection getPrincipals() { |
| return this.principals; |
| } |
| |
| public void setPrincipals(PrincipalCollection principals) { |
| this.principals = principals; |
| } |
| |
| public Object getCredentials() { |
| return credentials; |
| } |
| |
| public void setCredentials(Object credentials) { |
| this.credentials = credentials; |
| } |
| |
| public boolean isLocked() { |
| return locked; |
| } |
| |
| public void setLocked(boolean locked) { |
| this.locked = locked; |
| } |
| |
| public boolean isCredentialsExpired() { |
| return credentialsExpired; |
| } |
| |
| public void setCredentialsExpired(boolean credentialsExpired) { |
| this.credentialsExpired = credentialsExpired; |
| } |
| |
| /*-------------------------------------------- |
| | M E T H O D S | |
| ============================================*/ |
| /** |
| * Merges (adds) the specified Account data into this instance. |
| * |
| * This allows an instance of this class to be an <em>aggregation</em>, or <em>composition</em> of account data |
| * from across multiple <code>Realm</code>s <tt>Realm</tt>s, not just one realm. |
| * |
| * <p>This is useful in a multi-realm authentication configuration - the individual <tt>Account</tt> |
| * objects obtained from each realm can be {@link #merge merged} into this object. This single object can then be |
| * returned at the end of the authentication process, giving the impression of a single underlying |
| * realm/data source. |
| * |
| * @param otherAccount the account whos data will be merged (added) into this instance. |
| */ |
| @SuppressWarnings({"unchecked"}) |
| public void merge(Account otherAccount) { |
| if (otherAccount == null) { |
| return; |
| } |
| |
| PrincipalCollection otherPrincipals = otherAccount.getPrincipals(); |
| if (otherPrincipals == null) { |
| return; |
| } |
| |
| PrincipalCollection thisPrincipals = getPrincipals(); |
| if (thisPrincipals == null) { |
| setPrincipals(otherPrincipals); |
| } else { |
| //TODO - I don't like these checks - should be interface-based - Les. |
| if ( !(thisPrincipals instanceof SimplePrincipalCollection) ) { |
| throw new IllegalStateException( "The " + getClass().getName() + " class expects its internal " + |
| PrincipalCollection.class.getName() + " instance to be an instance of the " + |
| SimplePrincipalCollection.class.getName() + " class." ); |
| } |
| if ( !(otherPrincipals instanceof SimplePrincipalCollection) ) { |
| throw new IllegalArgumentException( "The " + getClass().getName() + " class expects the " + |
| "account argument's internal " + |
| PrincipalCollection.class.getName() + " instance to be an instance of the " + |
| SimplePrincipalCollection.class.getName() + " class." ); |
| } |
| ((SimplePrincipalCollection)thisPrincipals).merge((SimplePrincipalCollection)otherPrincipals); |
| setPrincipals(thisPrincipals); |
| } |
| |
| Object otherCredentials = otherAccount.getCredentials(); |
| Object thisCredentials = getCredentials(); |
| if ( thisCredentials == null ) { |
| setCredentials(otherCredentials); |
| } else { |
| HashSet set = new HashSet(); |
| if (thisCredentials instanceof Collection) { |
| set.addAll((Collection) thisCredentials); |
| } else { |
| set.add(thisCredentials); |
| } |
| if (otherCredentials instanceof Collection) { |
| set.addAll((Collection) otherCredentials); |
| } else { |
| set.add(otherCredentials); |
| } |
| setCredentials(set); |
| } |
| |
| if (otherAccount.isLocked()) { |
| setLocked(true); |
| } |
| |
| if (otherAccount.isCredentialsExpired()) { |
| setCredentialsExpired(true); |
| } |
| } |
| |
| public int hashCode() { |
| return (getPrincipals() != null ? getPrincipals().hashCode() : 0); |
| } |
| |
| public boolean equals(Object o) { |
| if (o == this) { |
| return true; |
| } |
| if (o instanceof SimpleAccount) { |
| SimpleAccount sa = (SimpleAccount) o; |
| //principal should be unique across the application, so only check this for equality: |
| return (getPrincipals() != null ? getPrincipals().equals(sa.getPrincipals()) : sa.getPrincipals() == null); |
| } |
| return false; |
| } |
| |
| public String toString() { |
| return getPrincipals() != null ? getPrincipals().toString() : "empty"; |
| } |
| } |