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 module hunt.shiro.authc.SimpleAccount; 20 21 import hunt.shiro.authc.Account; 22 import hunt.shiro.authc.AuthenticationInfo; 23 import hunt.shiro.authc.MergableAuthenticationInfo; 24 import hunt.shiro.authc.SaltedAuthenticationInfo; 25 import hunt.shiro.authc.SimpleAuthenticationInfo; 26 27 import hunt.shiro.authz.permission.Permission; 28 import hunt.shiro.authz.SimpleAuthorizationInfo; 29 import hunt.shiro.subject.PrincipalCollection; 30 import hunt.shiro.subject.SimplePrincipalCollection; 31 import hunt.shiro.util.ByteSource; 32 33 import hunt.collection; 34 35 36 /** 37 * Simple implementation of the {@link hunt.shiro.authc.Account} interface that 38 * contains principal and credential and authorization information (roles and permissions) as instance variables and 39 * exposes them via getters and setters using standard JavaBean notation. 40 * 41 */ 42 class SimpleAccount : Account, MergableAuthenticationInfo, SaltedAuthenticationInfo { 43 44 /*-------------------------------------------- 45 | I N S T A N C E V A R I A B L E S | 46 ============================================*/ 47 /** 48 * The authentication information (principals and credentials) for this account. 49 */ 50 private SimpleAuthenticationInfo authcInfo; 51 52 /** 53 * The authorization information for this account. 54 */ 55 private SimpleAuthorizationInfo authzInfo; 56 57 /** 58 * Indicates this account is locked. This isn't honored by all <tt>Realms</tt> but is honored by 59 * {@link hunt.shiro.realm.SimpleAccountRealm}. 60 */ 61 private bool locked; 62 63 /** 64 * Indicates credentials on this account are expired. This isn't honored by all <tt>Realms</tt> but is honored by 65 * {@link hunt.shiro.realm.SimpleAccountRealm}. 66 */ 67 private bool credentialsExpired; 68 69 /*-------------------------------------------- 70 | C O N S T R U C T O R S | 71 ============================================*/ 72 73 /** 74 * Default no-argument constructor. 75 */ 76 this() { 77 } 78 79 /** 80 * Constructs a SimpleAccount instance for the specified realm with the given principals and credentials. 81 * 82 * @param principal the 'primary' identifying attribute of the account, for example, a user id or username. 83 * @param credentials the credentials that verify identity for the account 84 * @param realmName the name of the realm that accesses this account data 85 */ 86 this(Object principal, Object credentials, string realmName) { 87 auto principalCast = cast(PrincipalCollection)principal; 88 this(principalCast !is null ? principalCast : new SimplePrincipalCollection(principal, realmName), credentials); 89 } 90 91 /** 92 * Constructs a SimpleAccount instance for the specified realm with the given principals, hashedCredentials and 93 * credentials salt used when hashing the credentials. 94 * 95 * @param principal the 'primary' identifying attribute of the account, for example, a user id or username. 96 * @param hashedCredentials the credentials that verify identity for the account 97 * @param credentialsSalt the salt used when hashing the credentials 98 * @param realmName the name of the realm that accesses this account data 99 * @see hunt.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher 100 */ 101 this(Object principal, Object hashedCredentials, ByteSource credentialsSalt, string realmName) { 102 auto principalCast = cast(PrincipalCollection)principal; 103 this(principalCast !is null ? principalCast : new SimplePrincipalCollection(principal, realmName), 104 hashedCredentials, credentialsSalt); 105 } 106 107 /** 108 * Constructs a SimpleAccount instance for the specified realm with the given principals and credentials. 109 * 110 * @param principals the identifying attributes of the account, at least one of which should be considered the 111 * account's 'primary' identifying attribute, for example, a user id or username. 112 * @param credentials the credentials that verify identity for the account 113 * @param realmName the name of the realm that accesses this account data 114 */ 115 this(Collection!Object principals, Object credentials, string realmName) { 116 this(new SimplePrincipalCollection(principals, realmName), credentials); 117 } 118 119 /** 120 * Constructs a SimpleAccount instance for the specified principals and credentials. 121 * 122 * @param principals the identifying attributes of the account, at least one of which should be considered the 123 * account's 'primary' identifying attribute, for example, a user id or username. 124 * @param credentials the credentials that verify identity for the account 125 */ 126 this(PrincipalCollection principals, Object credentials) { 127 this.authcInfo = new SimpleAuthenticationInfo(principals, credentials); 128 this.authzInfo = new SimpleAuthorizationInfo(); 129 } 130 131 /** 132 * Constructs a SimpleAccount instance for the specified principals and credentials. 133 * 134 * @param principals the identifying attributes of the account, at least one of which should be considered the 135 * account's 'primary' identifying attribute, for example, a user id or username. 136 * @param hashedCredentials the hashed credentials that verify identity for the account 137 * @param credentialsSalt the salt used when hashing the credentials 138 * @see hunt.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher 139 */ 140 this(PrincipalCollection principals, Object hashedCredentials, ByteSource credentialsSalt) { 141 this.authcInfo = new SimpleAuthenticationInfo(principals, hashedCredentials, credentialsSalt); 142 this.authzInfo = new SimpleAuthorizationInfo(); 143 } 144 145 /** 146 * Constructs a SimpleAccount instance for the specified principals and credentials, with the assigned roles. 147 * 148 * @param principals the identifying attributes of the account, at least one of which should be considered the 149 * account's 'primary' identifying attribute, for example, a user id or username. 150 * @param credentials the credentials that verify identity for the account 151 * @param roles the names of the roles assigned to this account. 152 */ 153 this(PrincipalCollection principals, Object credentials, Set!(string) roles) { 154 this.authcInfo = new SimpleAuthenticationInfo(principals, credentials); 155 this.authzInfo = new SimpleAuthorizationInfo(roles); 156 } 157 158 /** 159 * Constructs a SimpleAccount instance for the specified realm with the given principal and credentials, with the 160 * the assigned roles and permissions. 161 * 162 * @param principal the 'primary' identifying attributes of the account, for example, a user id or username. 163 * @param credentials the credentials that verify identity for the account 164 * @param realmName the name of the realm that accesses this account data 165 * @param roleNames the names of the roles assigned to this account. 166 * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms). 167 */ 168 this(Object principal, Object credentials, string realmName, Set!(string) roleNames, Set!(Permission) permissions) { 169 this.authcInfo = new SimpleAuthenticationInfo(new SimplePrincipalCollection(principal, realmName), credentials); 170 this.authzInfo = new SimpleAuthorizationInfo(roleNames); 171 this.authzInfo.setObjectPermissions(permissions); 172 } 173 174 /** 175 * Constructs a SimpleAccount instance for the specified realm with the given principals and credentials, with the 176 * the assigned roles and permissions. 177 * 178 * @param principals the identifying attributes of the account, at least one of which should be considered the 179 * account's 'primary' identifying attribute, for example, a user id or username. 180 * @param credentials the credentials that verify identity for the account 181 * @param realmName the name of the realm that accesses this account data 182 * @param roleNames the names of the roles assigned to this account. 183 * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms). 184 */ 185 this(Collection!Object principals, Object credentials, string realmName, Set!(string) roleNames, 186 Set!(Permission) permissions) { 187 this.authcInfo = new SimpleAuthenticationInfo(new SimplePrincipalCollection(principals, realmName), credentials); 188 this.authzInfo = new SimpleAuthorizationInfo(roleNames); 189 this.authzInfo.setObjectPermissions(permissions); 190 } 191 192 /** 193 * Constructs a SimpleAccount instance from the given principals and credentials, with the 194 * the assigned roles and permissions. 195 * 196 * @param principals the identifying attributes of the account, at least one of which should be considered the 197 * account's 'primary' identifying attribute, for example, a user id or username. 198 * @param credentials the credentials that verify identity for the account 199 * @param roleNames the names of the roles assigned to this account. 200 * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms). 201 */ 202 this(PrincipalCollection principals, Object credentials, Set!(string) roleNames, Set!(Permission) permissions) { 203 this.authcInfo = new SimpleAuthenticationInfo(principals, credentials); 204 this.authzInfo = new SimpleAuthorizationInfo(roleNames); 205 this.authzInfo.setObjectPermissions(permissions); 206 } 207 208 /*-------------------------------------------- 209 | A C C E S S O R S / M O D I F I E R S | 210 ============================================*/ 211 212 /** 213 * Returns the principals, aka the identifying attributes (username, user id, first name, last name, etc) of this 214 * Account. 215 * 216 * @return all the principals, aka the identifying attributes, of this Account. 217 */ 218 PrincipalCollection getPrincipals() @trusted nothrow { 219 return authcInfo.getPrincipals(); 220 } 221 222 /** 223 * Sets the principals, aka the identifying attributes (username, user id, first name, last name, etc) of this 224 * Account. 225 * 226 * @param principals all the principals, aka the identifying attributes, of this Account. 227 * @see Account#getPrincipals() 228 */ 229 void setPrincipals(PrincipalCollection principals) { 230 this.authcInfo.setPrincipals(principals); 231 } 232 233 234 /** 235 * Simply returns <code>this.authcInfo.getCredentials</code>. The <code>authcInfo</code> attribute is constructed 236 * via the constructors to wrap the input arguments. 237 * 238 * @return this Account's credentials. 239 */ 240 Object getCredentials() { 241 return authcInfo.getCredentials(); 242 } 243 244 /** 245 * Sets this Account's credentials that verify one or more of the Account's 246 * {@link #getPrincipals() principals}, such as a password or private key. 247 * 248 * @param credentials the credentials associated with this Account that verify one or more of the Account principals. 249 * @see hunt.shiro.authc.Account#getCredentials() 250 */ 251 void setCredentials(Object credentials) { 252 this.authcInfo.setCredentials(credentials); 253 } 254 255 /** 256 * Returns the salt used to hash this Account's credentials (eg for password hashing), or {@code null} if no salt 257 * was used or credentials were not hashed at all. 258 * 259 * @return the salt used to hash this Account's credentials (eg for password hashing), or {@code null} if no salt 260 * was used or credentials were not hashed at all. 261 */ 262 ByteSource getCredentialsSalt() { 263 return this.authcInfo.getCredentialsSalt(); 264 } 265 266 /** 267 * Sets the salt to use to hash this Account's credentials (eg for password hashing), or {@code null} if no salt 268 * is used or credentials are not hashed at all. 269 * 270 * @param salt the salt to use to hash this Account's credentials (eg for password hashing), or {@code null} if no 271 * salt is used or credentials are not hashed at all. 272 */ 273 void setCredentialsSalt(ByteSource salt) { 274 this.authcInfo.setCredentialsSalt(salt); 275 } 276 277 /** 278 * Returns <code>this.authzInfo.getRoles();</code> 279 * 280 * @return the Account's assigned roles. 281 */ 282 Collection!(string) getRoles() { 283 return authzInfo.getRoles(); 284 } 285 286 /** 287 * Sets the Account's assigned roles. Simply calls <code>this.authzInfo.setRoles(roles)</code>. 288 * 289 * @param roles the Account's assigned roles. 290 * @see Account#getRoles() 291 */ 292 void setRoles(Set!(string) roles) { 293 this.authzInfo.setRoles(roles); 294 } 295 296 /** 297 * Adds a role to this Account's set of assigned roles. Simply delegates to 298 * <code>this.authzInfo.addRole(role)</code>. 299 * 300 * @param role a role to assign to this Account. 301 */ 302 void addRole(string role) { 303 this.authzInfo.addRole(role); 304 } 305 306 /** 307 * Adds one or more roles to this Account's set of assigned roles. Simply delegates to 308 * <code>this.authzInfo.addRoles(roles)</code>. 309 * 310 * @param roles one or more roles to assign to this Account. 311 */ 312 void addRole(Collection!(string) roles) { 313 this.authzInfo.addRoles(roles); 314 } 315 316 /** 317 * Returns all string-based permissions assigned to this Account. Simply delegates to 318 * <code>this.authzInfo.getStringPermissions()</code>. 319 * 320 * @return all string-based permissions assigned to this Account. 321 */ 322 Collection!(string) getStringPermissions() { 323 return authzInfo.getStringPermissions(); 324 } 325 326 /** 327 * Sets the string-based permissions assigned to this Account. Simply delegates to 328 * <code>this.authzInfo.setStringPermissions(permissions)</code>. 329 * 330 * @param permissions all string-based permissions assigned to this Account. 331 * @see hunt.shiro.authc.Account#getStringPermissions() 332 */ 333 void setStringPermissions(Set!(string) permissions) { 334 this.authzInfo.setStringPermissions(permissions); 335 } 336 337 /** 338 * Assigns a string-based permission directly to this Account (not to any of its realms). 339 * 340 * @param permission the string-based permission to assign. 341 */ 342 void addStringPermission(string permission) { 343 this.authzInfo.addStringPermission(permission); 344 } 345 346 /** 347 * Assigns one or more string-based permissions directly to this Account (not to any of its realms). 348 * 349 * @param permissions one or more string-based permissions to assign. 350 */ 351 void addStringPermissions(Collection!(string) permissions) { 352 this.authzInfo.addStringPermissions(permissions); 353 } 354 355 /** 356 * Returns all object-based permissions assigned directly to this Account (not any of its realms). 357 * 358 * @return all object-based permissions assigned directly to this Account (not any of its realms). 359 */ 360 Collection!(Permission) getObjectPermissions() { 361 return authzInfo.getObjectPermissions(); 362 } 363 364 /** 365 * Sets all object-based permissions assigned directly to this Account (not any of its realms). 366 * 367 * @param permissions the object-based permissions to assign directly to this Account. 368 */ 369 void setObjectPermissions(Set!(Permission) permissions) { 370 this.authzInfo.setObjectPermissions(permissions); 371 } 372 373 /** 374 * Assigns an object-based permission directly to this Account (not any of its realms). 375 * 376 * @param permission the object-based permission to assign directly to this Account (not any of its realms). 377 */ 378 void addObjectPermission(Permission permission) { 379 this.authzInfo.addObjectPermission(permission); 380 } 381 382 /** 383 * Assigns one or more object-based permissions directly to this Account (not any of its realms). 384 * 385 * @param permissions one or more object-based permissions to assign directly to this Account (not any of its realms). 386 */ 387 void addObjectPermissions(Collection!(Permission) permissions) { 388 this.authzInfo.addObjectPermissions(permissions); 389 } 390 391 /** 392 * Returns <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise. 393 * 394 * @return <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise. 395 */ 396 bool isLocked() { 397 return locked; 398 } 399 400 /** 401 * Sets whether or not the account is locked and can be used to login. 402 * 403 * @param locked <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise. 404 */ 405 void setLocked(bool locked) { 406 this.locked = locked; 407 } 408 409 /** 410 * Returns whether or not the Account's credentials are expired. This usually indicates that the Subject or an application 411 * administrator would need to change the credentials before the account could be used. 412 * 413 * @return whether or not the Account's credentials are expired. 414 */ 415 bool isCredentialsExpired() { 416 return credentialsExpired; 417 } 418 419 /** 420 * Sets whether or not the Account's credentials are expired. A <code>true</code> value indicates that the Subject 421 * or application administrator would need to change their credentials before the account could be used. 422 * 423 * @param credentialsExpired <code>true</code> if this Account's credentials are expired and need to be changed, 424 * <code>false</code> otherwise. 425 */ 426 void setCredentialsExpired(bool credentialsExpired) { 427 this.credentialsExpired = credentialsExpired; 428 } 429 430 431 /** 432 * Merges the specified <code>AuthenticationInfo</code> into this <code>Account</code>. 433 * <p/> 434 * If the specified argument is also an instance of {@link SimpleAccount SimpleAccount}, the 435 * {@link #isLocked()} and {@link #isCredentialsExpired()} attributes are merged (set on this instance) as well 436 * (only if their values are <code>true</code>). 437 * 438 * @param info the <code>AuthenticationInfo</code> to merge into this account. 439 */ 440 void merge(AuthenticationInfo info) { 441 authcInfo.merge(info); 442 443 // Merge SimpleAccount specific info\ 444 SimpleAccount infoCast = cast(SimpleAccount)info; 445 if (infoCast !is null) { 446 SimpleAccount otherAccount = infoCast; 447 if (otherAccount.isLocked()) { 448 setLocked(true); 449 } 450 451 if (otherAccount.isCredentialsExpired()) { 452 setCredentialsExpired(true); 453 } 454 } 455 } 456 457 /** 458 * If the {@link #getPrincipals() principals} are not null, returns <code>principals.hashCode()</code>, otherwise 459 * returns 0 (zero). 460 * 461 * @return <code>principals.hashCode()</code> if they are not null, 0 (zero) otherwise. 462 */ 463 override size_t toHash() @trusted nothrow { 464 PrincipalCollection pc = getPrincipals(); 465 return (pc !is null ? (cast(Object)pc).toHash() : 0); 466 } 467 468 /** 469 * Returns <code>true</code> if the specified object is also a {@link SimpleAccount SimpleAccount} and its 470 * {@link #getPrincipals() principals} are equal to this object's <code>principals</code>, <code>false</code> otherwise. 471 * 472 * @param o the object to test for equality. 473 * @return <code>true</code> if the specified object is also a {@link SimpleAccount SimpleAccount} and its 474 * {@link #getPrincipals() principals} are equal to this object's <code>principals</code>, <code>false</code> otherwise. 475 */ 476 override bool opEquals(Object o) { 477 if (o == this) { 478 return true; 479 } 480 auto oCast = cast(SimpleAccount)o; 481 if (oCast !is null) { 482 SimpleAccount sa = oCast; 483 //principal should be unique across the application, so only check this for equality: 484 return (getPrincipals() !is null ? getPrincipals() == sa.getPrincipals() : sa.getPrincipals() is null); 485 } 486 return false; 487 } 488 489 /** 490 * Returns {@link #getPrincipals() principals}.toString() if they are not null, otherwise prints out the string 491 * "empty" 492 * 493 * @return the string representation of this Account object. 494 */ 495 override string toString() { 496 PrincipalCollection pc = getPrincipals(); 497 return pc !is null ? (cast(Object)pc).toString() : "empty"; 498 } 499 500 }