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.pam.FirstSuccessfulStrategy; 20 21 import hunt.shiro.authc.pam.AbstractAuthenticationStrategy; 22 23 import hunt.shiro.Exceptions; 24 import hunt.shiro.authc.AuthenticationInfo; 25 import hunt.shiro.authc.AuthenticationToken; 26 import hunt.shiro.realm.Realm; 27 import hunt.shiro.subject.PrincipalCollection; 28 29 import hunt.collection; 30 31 /** 32 * {@link AuthenticationStrategy} implementation that only accepts the account data from 33 * the first successfully consulted Realm and ignores all subsequent realms. This is slightly 34 * different behavior than {@link AtLeastOneSuccessfulStrategy}, so please review both to see 35 * which one meets your needs better. 36 * 37 * @see AtLeastOneSuccessfulStrategy AtLeastOneSuccessfulAuthenticationStrategy 38 */ 39 class FirstSuccessfulStrategy : AbstractAuthenticationStrategy { 40 41 /** 42 * Returns {@code null} immediately, relying on this class's {@link #merge merge} implementation to return 43 * only the first {@code info} object it encounters, ignoring all subsequent ones. 44 */ 45 override AuthenticationInfo beforeAllAttempts(Realm[] realms, AuthenticationToken token){ 46 return null; 47 } 48 49 private static bool isEmpty(PrincipalCollection pc) { 50 return pc is null || pc.isEmpty(); 51 } 52 53 /** 54 * Returns the specified {@code aggregate} instance if is non null and valid (that is, has principals and they are 55 * not empty) immediately, or, if it is null or not valid, the {@code info} argument is returned instead. 56 * <p/> 57 * This logic ensures that the first valid info encountered is the one retained and all subsequent ones are ignored, 58 * since this strategy mandates that only the info from the first successfully authenticated realm be used. 59 */ 60 override protected AuthenticationInfo merge(AuthenticationInfo info, AuthenticationInfo aggregate) { 61 if (aggregate !is null && isEmpty(aggregate.getPrincipals())) { 62 return aggregate; 63 } 64 return info !is null ? info : aggregate; 65 } 66 }