1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.apache.shiro.authc; 20 21 import org.apache.shiro.lang.util.ByteSource; 22 import org.apache.shiro.lang.util.SimpleByteSource; 23 import org.apache.shiro.subject.MutablePrincipalCollection; 24 import org.apache.shiro.subject.PrincipalCollection; 25 import org.apache.shiro.subject.SimplePrincipalCollection; 26 27 import java.util.Collection; 28 import java.util.HashSet; 29 import java.util.Objects; 30 import java.util.Set; 31 32 33 /** 34 * Simple implementation of the {@link org.apache.shiro.authc.MergableAuthenticationInfo} interface that holds the principals and 35 * credentials. 36 * 37 * @see org.apache.shiro.realm.AuthenticatingRealm 38 * @since 0.9 39 */ 40 public class SimpleAuthenticationInfo implements MergableAuthenticationInfo, SaltedAuthenticationInfo { 41 42 private static final long serialVersionUID = 5390456512469696779L; 43 /** 44 * The principals identifying the account associated with this AuthenticationInfo instance. 45 */ 46 protected PrincipalCollection principals; 47 /** 48 * The credentials verifying the account principals. 49 */ 50 protected Object credentials; 51 52 /** 53 * Any salt used in hashing the credentials. 54 * 55 * @since 1.1 56 */ 57 protected ByteSource credentialsSalt = SimpleByteSource.empty(); 58 59 /** 60 * Default no-argument constructor. 61 */ 62 public SimpleAuthenticationInfo() { 63 } 64 65 /** 66 * Constructor that takes in a single 'primary' principal of the account and its corresponding credentials, 67 * associated with the specified realm. 68 * <p/> 69 * This is a convenience constructor and will construct a {@link PrincipalCollection PrincipalCollection} based 70 * on the {@code principal} and {@code realmName} argument. 71 * 72 * @param principal the 'primary' principal associated with the specified realm. 73 * @param credentials the credentials that verify the given principal. 74 * @param realmName the realm from where the principal and credentials were acquired. 75 */ 76 public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) { 77 this.principals = new SimplePrincipalCollection(principal, realmName); 78 this.credentials = credentials; 79 } 80 81 /** 82 * Constructor that takes in a single 'primary' principal of the account, its corresponding hashed credentials, 83 * the salt used to hash the credentials, and the name of the realm to associate with the principals. 84 * <p/> 85 * This is a convenience constructor and will construct a {@link PrincipalCollection PrincipalCollection} based 86 * on the <code>principal</code> and <code>realmName</code> argument. 87 * 88 * @param principal the 'primary' principal associated with the specified realm. 89 * @param hashedCredentials the hashed credentials that verify the given principal. 90 * @param credentialsSalt the salt used when hashing the given hashedCredentials 91 * @param realmName the realm from where the principal and credentials were acquired. 92 * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher 93 * @since 1.1 94 */ 95 public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) { 96 this.principals = new SimplePrincipalCollection(principal, realmName); 97 this.credentials = hashedCredentials; 98 this.credentialsSalt = credentialsSalt; 99 } 100 101 /** 102 * Constructor that takes in an account's identifying principal(s) and its corresponding credentials that verify 103 * the principals. 104 * 105 * @param principals a Realm's account's identifying principal(s) 106 * @param credentials the accounts corresponding principals that verify the principals. 107 */ 108 public SimpleAuthenticationInfo(PrincipalCollection principals, Object credentials) { 109 this.principals = new SimplePrincipalCollection(principals); 110 this.credentials = credentials; 111 } 112 113 /** 114 * Constructor that takes in an account's identifying principal(s), hashed credentials used to verify the 115 * principals, and the salt used when hashing the credentials. 116 * 117 * @param principals a Realm's account's identifying principal(s) 118 * @param hashedCredentials the hashed credentials that verify the principals. 119 * @param credentialsSalt the salt used when hashing the hashedCredentials. 120 * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher 121 * @since 1.1 122 */ 123 public SimpleAuthenticationInfo(PrincipalCollection principals, Object hashedCredentials, ByteSource credentialsSalt) { 124 this.principals = new SimplePrincipalCollection(principals); 125 this.credentials = hashedCredentials; 126 this.credentialsSalt = credentialsSalt; 127 } 128 129 130 @Override 131 public PrincipalCollection getPrincipals() { 132 return principals; 133 } 134 135 /** 136 * Sets the identifying principal(s) represented by this instance. 137 * 138 * @param principals the identifying attributes of the corresponding Realm account. 139 */ 140 public void setPrincipals(PrincipalCollection principals) { 141 this.principals = principals; 142 } 143 144 @Override 145 public Object getCredentials() { 146 return credentials; 147 } 148 149 /** 150 * Sets the credentials that verify the principals/identity of the associated Realm account. 151 * 152 * @param credentials attribute(s) that verify the account's identity/principals, such as a password or private key. 153 */ 154 public void setCredentials(Object credentials) { 155 this.credentials = credentials; 156 } 157 158 /** 159 * Returns the salt used to hash the credentials, or {@code null} if no salt was used or credentials were not 160 * hashed at all. 161 * <p/> 162 * Note that this attribute is <em>NOT</em> handled in the 163 * {@link #merge(AuthenticationInfo) merge} method - a hash salt is only useful within a single realm (as each 164 * realm will perform it's own Credentials Matching logic), and once finished in that realm, Shiro has no further 165 * use for salts. Therefore it doesn't make sense to 'merge' salts in a multi-realm scenario. 166 * 167 * @return the salt used to hash the credentials, or {@code null} if no salt was used or credentials were not 168 * hashed at all. 169 * @since 1.1 170 */ 171 @Override 172 public ByteSource getCredentialsSalt() { 173 return credentialsSalt; 174 } 175 176 /** 177 * Sets the salt used to hash the credentials, or {@code null} if no salt was used or credentials were not 178 * hashed at all. 179 * <p/> 180 * Note that this attribute is <em>NOT</em> handled in the 181 * {@link #merge(AuthenticationInfo) merge} method - a hash salt is only useful within a single realm (as each 182 * realm will perform it's own Credentials Matching logic), and once finished in that realm, Shiro has no further 183 * use for salts. Therefore it doesn't make sense to 'merge' salts in a multi-realm scenario. 184 * 185 * @param salt the salt used to hash the credentials, or {@code null} if no salt was used or credentials were not 186 * hashed at all. 187 * @since 1.1 188 */ 189 public void setCredentialsSalt(ByteSource salt) { 190 this.credentialsSalt = salt; 191 } 192 193 /** 194 * Takes the specified <code>info</code> argument and adds its principals and credentials into this instance. 195 * 196 * @param info the <code>AuthenticationInfo</code> to add into this instance. 197 */ 198 @Override 199 @SuppressWarnings({"unchecked", "checkstyle:NPathComplexity"}) 200 public void merge(AuthenticationInfo info) { 201 if (info == null || info.getPrincipals() == null || info.getPrincipals().isEmpty()) { 202 return; 203 } 204 205 if (this.principals == null) { 206 this.principals = info.getPrincipals(); 207 } else { 208 if (!(this.principals instanceof MutablePrincipalCollection)) { 209 this.principals = new SimplePrincipalCollection(this.principals); 210 } 211 ((MutablePrincipalCollection) this.principals).addAll(info.getPrincipals()); 212 } 213 214 //only mess with a salt value if we don't have one yet. It doesn't make sense 215 //to merge salt values from different realms because a salt is used only within 216 //the realm's credential matching process. But if the current instance's salt 217 //is null, then it can't hurt to pull in a non-null value if one exists. 218 // 219 //since 1.1: 220 if (this.credentialsSalt == null && info instanceof SaltedAuthenticationInfo) { 221 this.credentialsSalt = ((SaltedAuthenticationInfo) info).getCredentialsSalt(); 222 } 223 224 Object thisCredentials = getCredentials(); 225 Object otherCredentials = info.getCredentials(); 226 227 if (otherCredentials == null) { 228 return; 229 } 230 231 if (thisCredentials == null) { 232 this.credentials = otherCredentials; 233 return; 234 } 235 236 if (!(thisCredentials instanceof Collection)) { 237 Set newSet = new HashSet(); 238 newSet.add(thisCredentials); 239 setCredentials(newSet); 240 } 241 242 // At this point, the credentials should be a collection 243 Collection credentialCollection = (Collection) getCredentials(); 244 if (otherCredentials instanceof Collection) { 245 credentialCollection.addAll((Collection) otherCredentials); 246 } else { 247 credentialCollection.add(otherCredentials); 248 } 249 } 250 251 /** 252 * Returns <code>true</code> if the Object argument is an <code>instanceof SimpleAuthenticationInfo</code> and 253 * its {@link #getPrincipals() principals} are equal to this instance's principals, <code>false</code> otherwise. 254 * 255 * @param o the object to compare for equality. 256 * @return <code>true</code> if the Object argument is an <code>instanceof SimpleAuthenticationInfo</code> and 257 * its {@link #getPrincipals() principals} are equal to this instance's principals, <code>false</code> otherwise. 258 */ 259 @Override 260 public boolean equals(Object o) { 261 if (this == o) { 262 return true; 263 } 264 if (!(o instanceof SimpleAuthenticationInfo)) { 265 return false; 266 } 267 268 SimpleAuthenticationInfo that = (SimpleAuthenticationInfo) o; 269 270 //noinspection RedundantIfStatement 271 if (!Objects.equals(principals, that.principals)) { 272 return false; 273 } 274 275 return true; 276 } 277 278 /** 279 * Returns the hashcode of the internal {@link #getPrincipals() principals} instance. 280 * 281 * @return the hashcode of the internal {@link #getPrincipals() principals} instance. 282 */ 283 @Override 284 public int hashCode() { 285 return (principals != null ? principals.hashCode() : 0); 286 } 287 288 /** 289 * Simple implementation that merely returns <code>{@link #getPrincipals() principals}.toString()</code> 290 * 291 * @return <code>{@link #getPrincipals() principals}.toString()</code> 292 */ 293 @Override 294 public String toString() { 295 return principals.toString(); 296 } 297 298 }