Apereo CAS 5.0.X中为我们提供了四种基于JDBC的AuthenticationHandler的实现,在cas-server-support-jdbc子模块中,下面一一对他们进行介绍。
Query
配置一个SQL语句,该SQL可以通过传入的用户名查询返回该用户的密码,然后与用户输入的密码进行比较,进行比较之前,可以配置加密过程。匹配结果将作为认证结果,如果对应的用户名不存在也将返回false。
@Override
protected HandlerResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential credential, final String originalPassword)
throws GeneralSecurityException, PreventedException {
if (StringUtils.isBlank(this.sql) || getJdbcTemplate() == null) {
throw new GeneralSecurityException("Authentication handler is not configured correctly. "
+ "No SQL statement or JDBC template is found.");
}
final String username = credential.getUsername();
final String password = credential.getPassword();
try {
final String dbPassword = getJdbcTemplate().queryForObject(this.sql, String.class, username);
if ((StringUtils.isNotBlank(originalPassword) && !this.matches(originalPassword, dbPassword))
|| (StringUtils.isBlank(originalPassword) && !StringUtils.equals(password, dbPassword))) {
throw new FailedLoginException("Password does not match value on record.");
}
} catch (final IncorrectResultSizeDataAccessException e) {
if (e.getActualSize() == 0) {
throw new AccountNotFoundException(username + " not found with SQL query");
}
throw new FailedLoginException("Multiple records found for " + username);
} catch (final DataAccessException e) {
throw new PreventedException("SQL exception while executing query for " + username, e);
}
return createHandlerResult(credential, this.principalFactory.createPrincipal(username), null);
}
QueryAndEncode
跟上边一样的模式,不过密码再加密的时候可以配置加盐处理。
@Override
protected HandlerResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential transformedCredential)
throws GeneralSecurityException, PreventedException {
if (StringUtils.isBlank(this.sql) || StringUtils.isBlank(this.algorithmName) || getJdbcTemplate() == null) {
throw new GeneralSecurityException("Authentication handler is not configured correctly");
}
final String username = transformedCredential.getUsername();
try {
final Map<String, Object> values = getJdbcTemplate().queryForMap(this.sql, username);
final String digestedPassword = digestEncodedPassword(transformedCredential.getPassword(), values);
if (!values.get(this.passwordFieldName).equals(digestedPassword)) {
throw new FailedLoginException("Password does not match value on record.");
}
return createHandlerResult(transformedCredential,
this.principalFactory.createPrincipal(username), null);
} catch (final IncorrectResultSizeDataAccessException e) {
if (e.getActualSize() == 0) {
throw new AccountNotFoundException(username + " not found with SQL query");
} else {
throw new FailedLoginException("Multiple records found for " + username);
}
} catch (final DataAccessException e) {
throw new PreventedException("SQL exception while executing query for " + username, e);
}
}
SearchModeSearch
通过查询指定的表的指定的用户名和指定的密码的记录是否存在来判断是否验证通过。
@Override
protected HandlerResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential credential)
throws GeneralSecurityException, PreventedException {
String sql = null;
if (StringUtils.isNotBlank(tableUsers) || StringUtils.isNotBlank(fieldUser) || StringUtils.isNotBlank(fieldPassword)) {
sql = "SELECT COUNT('x') FROM ".concat(this.tableUsers).concat(" WHERE ").concat(this.fieldUser)
.concat(" = ? AND ").concat(this.fieldPassword).concat("= ?");
}
if (StringUtils.isBlank(sql) || getJdbcTemplate() == null) {
throw new GeneralSecurityException("Authentication handler is not configured correctly. "
+ "No SQL statement or JDBC template found");
}
final String username = credential.getUsername();
try {
logger.debug("Executing SQL query {}", sql);
final int count = getJdbcTemplate().queryForObject(sql, Integer.class, username, credential.getPassword());
if (count == 0) {
throw new FailedLoginException(username + " not found with SQL query.");
}
return createHandlerResult(credential, this.principalFactory.createPrincipal(username), null);
} catch (final DataAccessException e) {
throw new PreventedException("SQL exception while executing query for " + username, e);
}
}
BindModeSearch
将试图以传入的用户名和密码从配置的DataSource中建立一个连接,如果连接成功,则表示认证成功,否则就是认证失败。
protected HandlerResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential credential)
throws GeneralSecurityException, PreventedException {
if (getDataSource() == null) {
throw new GeneralSecurityException("Authentication handler is not configured correctly");
}
Connection connection = null;
try {
final String username = credential.getUsername();
final String password = credential.getPassword();
connection = this.getDataSource().getConnection(username, password);
return createHandlerResult(credential, this.principalFactory.createPrincipal(username), null);
} catch (final SQLException e) {
throw new FailedLoginException(e.getMessage());
} catch (final Exception e) {
throw new PreventedException("Unexpected SQL connection error", e);
} finally {
if (connection != null) {
DataSourceUtils.releaseConnection(connection, this.getDataSource());
}
}
}