目前我们的webapps使用Spring Security(Acegi Security 1.0.3)进行用户名和密码验证。我最近被赋予了在框架中插入双因素身份验证(网格卡或令牌)的任务。
但是,Spring Security中有很多扩展点 - 所以如果你能给我一些关于我是否以正确的方式解决它的问题,我将不胜感激。
工作流程为:用户使用其用户名和密码登录>用户被发出网格卡挑战>验证成功后,他们将被授予访问权限。
这是我目前正在解决的解决方案。
SimpleFormController
(我称之为GridChallengeController
)。如果成功,将为用户分配GridUser
角色,并将重定向到他们最初请求的页面。代码:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
AcegiCrowdUserDetails details = (AcegiCrowdUserDetails) auth.getPrincipal();
details.addAuthority("GridUser");
UsernamePasswordAuthenticationToken existing = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(SecurityContextHolder.getContext().getAuthentication().getPrincipal(),
existing.getCredentials(), details.getAuthorities()));
SavedRequest saved = (SavedRequest) request.getSession().getAttribute(AbstractProcessingFilter.ACEGI_SAVED_REQUEST_KEY);
return new ModelAndView(new RedirectView(saved.getFullRequestUrl()));
org.acegisecurity.ui.ExceptionTranslationFilter
以允许另一个身份验证入口点。当accessDecisionManager
抛出TwoFactorAccessDeniedException
(扩展org.acegisecurity.AuthenticationException
)时,它会被触发。以下是相关方法:代码:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
private AuthenticationEntryPoint twoFactorAuthenticationEntryPoint;
...
try {
chain.doFilter(request, response);
} catch (TwoFactorAccessDeniedException ex) {
handleException(request, response, chain, ex);
} catch (AuthenticationException ex) {
handleException(request, response, chain, ex);
} catch (AccessDeniedException ex) {
handleException(request, response, chain, ex);
} catch (ServletException ex) {
...
}
}
private void handleException(ServletRequest request, ServletResponse response, FilterChain chain, AcegiSecurityException exception) throws IOException, ServletException {
if (exception instanceof TwoFactorAccessDeniedException) {
sendStartTwoFactorAuthentication(request, response, chain, (AuthenticationException) exception);
} else if (exception instanceof AuthenticationException) {
sendStartAuthentication(request, response, chain, (AuthenticationException) exception);
} else if (exception instanceof AccessDeniedException) {
...
}
}
private void sendStartTwoFactorAuthentication(ServletRequest request, ServletResponse response, FilterChain chain, AuthenticationException reason) throws ServletException, IOException {
twoFactorAuthenticationEntryPoint.commence((HttpServletRequest) request, (HttpServletResponse) response, reason);
}
org.acegisecurity.vote.AffirmativeBased
扩展为TwoFactorAccessDeniedException
(用户在使用其网卡进行身份验证时会被分配GridUser
个角色) 代码:
@Override
public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config) throws AccessDeniedException {
super.decide(authentication, object, config);
FilterInvocation f = (FilterInvocation) object;
if (!hasRole(authentication, "GridUser") && !hasRole(authentication, "ROLE_ANONYMOUS") && !f.getRequestUrl().equalsIgnoreCase("/gridchallenge.htm")) {
throw new TwoFactorAccessDeniedException("Need a grid logon");
}
}
以下是我的安全XML文件的相关摘要:
代码:
<bean id="exceptionTranslationFilter" class="authentication.TwoFactorExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<bean id="basicProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/acegilogin.jsp"/>
<property name="forceHttps" value="false"/>
</bean>
</property>
<property name="twoFactorAuthenticationEntryPoint">
<bean id="gridProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/gridchallenge.htm"/>
<property name="forceHttps" value="false"/>
</bean>
</property>
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage" value="/accessDenied.jsp"/>
</bean>
</property>
</bean>
<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager">
<bean class="authentication.TwoFactorAffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="false"/>
<property name="decisionVoters">
<list>
<ref bean="roleVoter"/>
<bean class="org.acegisecurity.vote.AuthenticatedVoter"/>
</list>
</property>
</bean>
</property>
<property name="objectDefinitionSource">
<value><![CDATA[
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/admin/**=Vaas_Administrator
/guard/**=Guard
/acegilogin.jsp=IS_AUTHENTICATED_ANONYMOUSLY
/gridchallenge.htm=IS_AUTHENTICATED_FULLY
/**=VaasUser
]]></value>
</property>
</bean>
我是否应该添加任何东西以使我的应用程序正常工作?