001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.shiro.authc;
020    
021    import org.apache.shiro.subject.MutablePrincipalCollection;
022    import org.apache.shiro.subject.PrincipalCollection;
023    import org.apache.shiro.subject.SimplePrincipalCollection;
024    
025    import java.util.Collection;
026    import java.util.HashSet;
027    import java.util.Set;
028    
029    
030    /**
031     * Simple implementation of the {@link org.apache.shiro.authc.MergableAuthenticationInfo} interface that holds the principals and
032     * credentials.
033     *
034     * @author Jeremy Haile
035     * @author Les Hazlewood
036     * @see org.apache.shiro.realm.AuthenticatingRealm
037     * @since 0.9
038     */
039    public class SimpleAuthenticationInfo implements MergableAuthenticationInfo {
040    
041        /**
042         * The principals identifying the account associated with this AuthenticationInfo instance.
043         */
044        protected PrincipalCollection principals;
045        /**
046         * The credentials verifying the account principals.
047         */
048        protected Object credentials;
049    
050        /**
051         * Default no-argument constructor.
052         */
053        public SimpleAuthenticationInfo() {
054        }
055    
056        /**
057         * Constructor that takes in a single 'primary' principal of the account and its corresponding credentials,
058         * associated with the specified realm.
059         * <p/>
060         * This is a convenience constructor and will construct a {@link PrincipalCollection PrincipalCollection} based
061         * on the <code>principal</code> and <code>realmName</code> argument.
062         *
063         * @param principal   the 'primary' principal associated with the specified realm.
064         * @param credentials the credentials that verify the given principal.
065         * @param realmName   the realm from where the principal and credentials were acquired.
066         */
067        public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) {
068            this.principals = new SimplePrincipalCollection(principal, realmName);
069            this.credentials = credentials;
070        }
071    
072        /**
073         * Constructor that takes in an account's identifying principal(s) and its corresponding credentials that verify
074         * the principals.
075         *
076         * @param principals  a Realm's account's identifying principal(s)
077         * @param credentials the accounts corresponding principals that verify the principals.
078         */
079        public SimpleAuthenticationInfo(PrincipalCollection principals, Object credentials) {
080            this.principals = new SimplePrincipalCollection(principals);
081            this.credentials = credentials;
082        }
083    
084    
085        public PrincipalCollection getPrincipals() {
086            return principals;
087        }
088    
089        /**
090         * Sets the identifying principal(s) represented by this instance.
091         *
092         * @param principals the indentifying attributes of the corresponding Realm account.
093         */
094        public void setPrincipals(PrincipalCollection principals) {
095            this.principals = principals;
096        }
097    
098        public Object getCredentials() {
099            return credentials;
100        }
101    
102        /**
103         * Sets the credentials that verify the principals/identity of the associated Realm account.
104         *
105         * @param credentials attribute(s) that verify the account's identity/principals, such as a password or private key.
106         */
107        public void setCredentials(Object credentials) {
108            this.credentials = credentials;
109        }
110    
111        /**
112         * Takes the specified <code>info</code> argument and adds its principals and credentials into this instance.
113         *
114         * @param info the <code>AuthenticationInfo</code> to add into this instance.
115         */
116        @SuppressWarnings("unchecked")
117        public void merge(AuthenticationInfo info) {
118            if (info == null || info.getPrincipals() == null || info.getPrincipals().isEmpty()) {
119                return;
120            }
121    
122            if (this.principals == null) {
123                this.principals = info.getPrincipals();
124            } else {
125                if (!(this.principals instanceof MutablePrincipalCollection)) {
126                    this.principals = new SimplePrincipalCollection(this.principals);
127                }
128                ((MutablePrincipalCollection) this.principals).addAll(info.getPrincipals());
129            }         
130    
131            Object thisCredentials = getCredentials();
132            Object otherCredentials = info.getCredentials();
133    
134            if (otherCredentials == null) {
135                return;
136            }
137    
138            if (thisCredentials == null) {
139                this.credentials = otherCredentials;
140                return;
141            }
142    
143            if (!(thisCredentials instanceof Collection)) {
144                Set newSet = new HashSet();
145                newSet.add(thisCredentials);
146                setCredentials(newSet);
147            }
148    
149            // At this point, the credentials should be a collection
150            Collection credentialCollection = (Collection) getCredentials();
151            if (otherCredentials instanceof Collection) {
152                credentialCollection.addAll((Collection) otherCredentials);
153            } else {
154                credentialCollection.add(otherCredentials);
155            }
156        }
157    
158        /**
159         * Returns <code>true</code> if the Object argument is an <code>instanceof SimpleAuthenticationInfo</code> and
160         * its {@link #getPrincipals() principals} are equal to this instance's principals, <code>false</code> otherwise.
161         *
162         * @param o the object to compare for equality.
163         * @return <code>true</code> if the Object argument is an <code>instanceof SimpleAuthenticationInfo</code> and
164         *         its {@link #getPrincipals() principals} are equal to this instance's principals, <code>false</code> otherwise.
165         */
166        public boolean equals(Object o) {
167            if (this == o) return true;
168            if (!(o instanceof SimpleAuthenticationInfo)) return false;
169    
170            SimpleAuthenticationInfo that = (SimpleAuthenticationInfo) o;
171    
172            //noinspection RedundantIfStatement
173            if (principals != null ? !principals.equals(that.principals) : that.principals != null) return false;
174    
175            return true;
176        }
177    
178        /**
179         * Returns the hashcode of the internal {@link #getPrincipals() principals} instance.
180         *
181         * @return the hashcode of the internal {@link #getPrincipals() principals} instance.
182         */
183        public int hashCode() {
184            return (principals != null ? principals.hashCode() : 0);
185        }
186    
187        /**
188         * Simple implementation that merely returns <code>{@link #getPrincipals() principals}.toString()</code>
189         *
190         * @return <code>{@link #getPrincipals() principals}.toString()</code>
191         */
192        public String toString() {
193            return principals.toString();
194        }
195    
196    }