ModularRealmAuthenticator 的源碼分析和配置
SecurityManager得到token信息后闲礼,通過調(diào)用authenticator.authenticate(token)方法,把身份驗證委托給內(nèi)置的Authenticator的實例進(jìn)行驗證砂心。authenticator通常是ModularRealmAuthenticator
實例,支持對一個或多個Realm實例進(jìn)行適配蛇耀。ModularRealmAuthenticator提供了一種可插拔的認(rèn)證風(fēng)格辩诞,你可以在此處插入自定義Realm實現(xiàn)。如果配置了多個Realm纺涤,ModularRealmAuthenticator會根據(jù)配置的AuthenticationStrategy(身份驗證策略)進(jìn)行多Realm認(rèn)證過程译暂。
注:如果應(yīng)用程序中僅配置了一個Realm抠忘,Realm將被直接調(diào)用而無需再配置認(rèn)證策略。判斷每個Realm是否支持提交的token外永,如果支持Realm就會調(diào)用getAuthenticationInfo(token)方法進(jìn)行認(rèn)證處理崎脉。
AuthenticationStrategy(身份驗證策略)會在后邊講解
public abstract class AbstractAuthenticator implements Authenticator, LogoutAware {
public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
if (token == null) {
throw new IllegalArgumentException("Method argument (authentication token) cannot be null.");
}
log.trace("Authentication attempt received for token [{}]", token);
AuthenticationInfo info;
try {
*// 調(diào)用 ModularRealmAuthenticator。 doAuthenticate(token) 方法*
info = doAuthenticate(token);
if (info == null) {
String msg = "No account information found for authentication token [" + token + "] by this " +
"Authenticator instance. Please check that it is configured correctly.";
throw new AuthenticationException(msg);
}
} catch (Throwable t) {
AuthenticationException ae = null;
if (t instanceof AuthenticationException) {
ae = (AuthenticationException) t;
}
if (ae == null) {
//Exception thrown was not an expected AuthenticationException. Therefore it is probably a little more
//severe or unexpected. So, wrap in an AuthenticationException, log to warn, and propagate:
String msg = "Authentication failed for token submission [" + token + "]. Possible unexpected " +
"error? (Typical or expected login exceptions should extend from AuthenticationException).";
ae = new AuthenticationException(msg, t);
if (log.isWarnEnabled())
log.warn(msg, t);
}
try {
notifyFailure(token, ae);
} catch (Throwable t2) {
if (log.isWarnEnabled()) {
String msg = "Unable to send notification for failed authentication attempt - listener error?. " +
"Please check your AuthenticationListener implementation(s). Logging sending exception " +
"and propagating original AuthenticationException instead...";
log.warn(msg, t2);
}
}
throw ae;
}
log.debug("Authentication successful for token [{}]. Returned account [{}]", token, info);
notifySuccess(token, info);
return info;
}
protected abstract AuthenticationInfo doAuthenticate(AuthenticationToken token)
throws AuthenticationException;
}
ModularRealmAuthenticator 源碼分析
public class ModularRealmAuthenticator extends AbstractAuthenticator {
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
assertRealmsConfigured();
Collection<Realm> realms = getRealms();
if (realms.size() == 1) {
return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
} else {
return doMultiRealmAuthentication(realms, authenticationToken);
}
}
}
①當(dāng)realm==1的時候
public class ModularRealmAuthenticator extends AbstractAuthenticator {
protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
if (!realm.supports(token)) {
String msg = "Realm [" + realm + "] does not support authentication token [" +
token + "]. Please ensure that the appropriate Realm implementation is " +
"configured correctly or that the realm accepts AuthenticationTokens of this type.";
throw new UnsupportedTokenException(msg);
}
// 去調(diào)用自定義realm 中的認(rèn)證方法
AuthenticationInfo info = realm.getAuthenticationInfo(token);
if (info == null) {
String msg = "Realm [" + realm + "] was unable to find account data for the " +
"submitted AuthenticationToken [" + token + "].";
throw new UnknownAccountException(msg);
}
return info;
}
}
當(dāng)realm個數(shù)大于1 的時候 realms!=1 這里會涉及到>AuthenticationStrategy(身份驗證策略)
根據(jù)策略進(jìn)行認(rèn)證結(jié)果
public class ModularRealmAuthenticator extends AbstractAuthenticator {
protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) {
// 獲得認(rèn)證策略
AuthenticationStrategy strategy = getAuthenticationStrategy();
AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);
if (log.isTraceEnabled()) {
log.trace("Iterating through {} realms for PAM authentication", realms.size());
}
for (Realm realm : realms) {
aggregate = strategy.beforeAttempt(realm, token, aggregate);
if (realm.supports(token)) {
log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm);
AuthenticationInfo info = null;
Throwable t = null;
try {
info = realm.getAuthenticationInfo(token);
} catch (Throwable throwable) {
t = throwable;
if (log.isDebugEnabled()) {
String msg = "Realm [" + realm + "] threw an exception during a multi-realm authentication attempt:";
log.debug(msg, t);
}
}
aggregate = strategy.afterAttempt(realm, token, info, aggregate, t);
} else {
log.debug("Realm [{}] does not support token {}. Skipping realm.", realm, token);
}
}
aggregate = strategy.afterAllAttempts(token, aggregate);
return aggregate;
}
}
// 去調(diào)用自定義realm 中的認(rèn)證方法
AuthenticationInfo info = realm.getAuthenticationInfo(token);
多realm 就是for循環(huán)調(diào)用 getAuthenticationInfo(token);
public class MyRealm extends AuthorizingRealm {
//public class MyRealm extends AuthenticatingRealm {
/**
* 認(rèn)證
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
String password = String.valueOf(usernamePasswordToken.getPassword());
ByteSource solt = ByteSource.Util.bytes(username);
if (username.equals("username") && password.equals("password")) {
return new SimpleAuthenticationInfo(username, password, getName());
}
return null;
}
}
進(jìn)行密碼比較
public abstract class AuthenticatingRealm extends CachingRealm implements Initializable {
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
CredentialsMatcher cm = getCredentialsMatcher();
if (cm != null) {
if (!cm.doCredentialsMatch(token, info)) {
//not successful - throw an exception to indicate this:
String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
throw new IncorrectCredentialsException(msg);
}
} else {
throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
"credentials during authentication. If you do not wish for credentials to be examined, you " +
"can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
}
}
}