我正在尝试使用grails-sporing-security-rest和grails-spring-security-ldap插件为REST API实施安全性。
流程应该是这样的,一旦实现了身份验证提供程序,它将使用身份验证机制对用户进行身份验证。
但是在我的情况下,我正在尝试验证JSON用户名和密码POST请求,以下是输出。
如果您观察到日志,则SpringSecurityLDAPTemplate身份验证成功,但是当请求转到下一个过滤器RestAuthenticationFilter时,它将显示Bad Credentials错误。这令人有些困惑。 / api / login是spring安全性端点,如果身份验证成功,它将使用用户名和密码,它应该返回适当的令牌,但是为什么又将其发送到RestAuthenticationFilter?
使用正确的用户名和密码:
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/login'; against '/api/**'
o.s.security.web.FilterChainProxy : /api/login at position 1 of 7 in additional filter chain; firing Filter: 'SecurityRequestHolderFilter'
o.s.security.web.FilterChainProxy : /api/login at position 2 of 7 in additional filter chain; firing Filter: 'MutableLogoutFilter'
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/login'; against '/logoff'
o.s.security.web.FilterChainProxy : /api/login at position 3 of 7 in additional filter chain; firing Filter: 'RestAuthenticationFilter'
g.p.s.rest.RestAuthenticationFilter : Actual URI is /api/login; endpoint URL is /api/login
g.p.s.rest.RestAuthenticationFilter : Applying authentication filter to this request
c.DefaultJsonPayloadCredentialsExtractor : Extracted credentials from JSON payload. Username: xxxxxxx, password: [PROTECTED]
g.p.s.rest.RestAuthenticationFilter : Trying to authenticate the request
o.s.s.authentication.ProviderManager : Authentication attempt using org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider
o.s.s.ldap.SpringSecurityLdapTemplate : Searching for entry under DN '', base = 'dc=xxx,dc=xxx,dc=xxx,dc=xxx', filter = '(&(objectClass=user)(userPrincipalName={0}))'
g.p.s.rest.RestAuthenticationFilter : Authentication failed: Bad credentials
g.p.s.r.token.bearer.BearerTokenReader : Looking for bearer token in Authorization header, query string or Form-Encoded body parameter
g.p.s.r.token.bearer.BearerTokenReader : No token found
g.p.s.r.token.bearer.BearerTokenReader : Token: null
.BearerTokenAuthenticationFailureHandler : Sending status code 401 and header WWW-Authenticate: Bearer
用户名和密码错误:
o.s.s.authentication.ProviderManager : Authentication attempt using org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider
ctiveDirectoryLdapAuthenticationProvider : Active Directory authentication failed: Supplied password was invalid
g.p.s.rest.RestAuthenticationFilter : Authentication failed: Bad credentials
Resources.Groovy
import myapp.MyUserDetailsContextMapper
import org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider
// Place your Spring DSL code here
beans = {
ldapAuthProvider1(ActiveDirectoryLdapAuthenticationProvider, "xxx" ,"xxxx" ) {
userDetailsContextMapper = ldapUserDetailsMapper
}
ldapUserDetailsMapper(MyUserDetailsContextMapper) {
}
}
application.groovy
grails.plugin.springsecurity.filterChain.chainMap = [
//Stateless chain
[
pattern: '/api/**',
filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter'
],
//Traditional, stateful chain
[
pattern: '/stateful/**',
filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
]
]
grails.plugin.springsecurity.rest.token.storage.jwt.secret="xyz1234dsgsd4546dfhg345745754785756856856785679fghfgj"
grails.plugin.springsecurity.rest.login.active=true
grails.plugin.springsecurity.rest.login.endpointUrl="/api/login"
grails.plugin.springsecurity.rest.login.failureStatusCode=401
application.yml-Grails配置
grails:
plugin:
springsecurity:
providerNames: ["ldapAuthProvider1","anonymousAuthenticationProvider"]
useSecurityEventListener: true
ldap:
search:
attributesToReturn: ['mail', 'displayName']
filter: '(sAMAccountName={0})'
searchSubtree: true
authorities:
retrieveDatabaseRoles: false
ignorePartialResultException: true
authenticator:
useBind: true
attributesToReturn: null
auth:
useAuthPassword: true
rest:
login:
useJsonCredentials: true
usernamePropertyName: username
passwordPropertyName: password
更新:
进一步解决了问题,并注意到了这一点。
下面的代码行位于 SpringSecurityLdapTemplate 类和方法 searchForSingleEntryInternal 中-从spring-security-ldap 4.2.3版本开始。从 ActiveDirectoryLdapAuthenticationProvider 类中调用该类以从LDAP中获取信息。
final DistinguishedName searchBaseDn = new DistinguishedName(base);
final NamingEnumeration<SearchResult> resultsEnum = ctx.search(searchBaseDn,
filter, params, buildControls(searchControls));
if (logger.isDebugEnabled()) {
logger.debug("Searching for entry under DN '" + ctxBaseDn + "', base = '"
+ searchBaseDn + "', filter = '" + filter + "'");
}
Set<DirContextOperations> results = new HashSet<DirContextOperations>();
try {
while (resultsEnum.hasMore()) {
SearchResult searchResult = resultsEnum.next();
DirContextAdapter dca = (DirContextAdapter) searchResult.getObject();
Assert.notNull(dca,
"No object returned by search, DirContext is not correctly configured");
在这种情况下,searchResult.getObject返回的null导致身份验证失败,但是我验证了自己能够从resultsEnum获取属性。
我们非常感谢您的协助。谢谢。
答案 0 :(得分:0)
这行代码是ActiveDirectoryAuthenticationProvider类的一部分,正在引起麻烦,因为它期望LdapContext对象的传递实际上为null。扩展了AbstractAuthenticationProvider并创建了自定义身份验证处理程序来解决该问题。
DirContextAdapter dca = (DirContextAdapter) searchResult.getObject();