2014年5月28日 星期三

Spring Security OAuth2 Client anonymous 存取 Oauth2 resource

spring-projects/spring-security-oauth 在這個專案有 OAuth1, OAuth2的 Server, Client實作,在 OAuth1 Client 存取 Server resource時是可以直接存取的,但在 OAuth2 Client的設計是要先登入才能存取 Server resource,如果要直接存取的話,則會出現錯誤如下

org.springframework.security.authentication.InsufficientAuthenticationException: Authentication is required to obtain an access token (anonymous not allowed)



這邊有一邊文章 (Integrating Google Calendar into a Wicket Application) 可以達到直接存取的目的,
作法大約如下:

1.實作一 class extends AbstractAuthenticationProcessingFilter, 最主要是在

  attemptAuthentication 內產生一個 TestingAuthenticationToken,只要是作為 anonymous登入用


   public class AnoAuthenicationProcessingFilter extends AbstractAuthenticationProcessingFilter {
private static java.util.logging.Logger log1 = java.util.logging.Logger.getLogger("");

    protected AnoAuthenicationProcessingFilter() {
    //super內的參數不可為空白
        super("/login.jsp");
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
   
        //Authentication authentication = new TestingAuthenticationToken(request.getRemoteAddr(), request.getRemoteAddr(), "ROLE_ANONYMOUS");
   
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
   
    if ( authentication == null) {
            log1.log(Level.WARNING,".........establish a new tem Test token for "+ request.getRemoteAddr());
    authentication = new TestingAuthenticationToken(request.getRemoteAddr(), request.getRemoteAddr(), "ROLE_ANONYMOUS");
            authentication.setAuthenticated(true);
    }
   
   
        return getAuthenticationManager().authenticate(authentication);
     
    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {

        if (SecurityContextHolder.getContext().getAuthentication() == null) {
            SecurityContextHolder.getContext().setAuthentication(attemptAuthentication((HttpServletRequest) req, (HttpServletResponse) res));

            if (logger.isDebugEnabled()) {
                logger.debug("Populated SecurityContextHolder with dummy token: '"
                        + SecurityContextHolder.getContext().getAuthentication() + "'");
            }
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("SecurityContextHolder not populated with dummy token, as it already contained: '"
                        + SecurityContextHolder.getContext().getAuthentication() + "'");
            }
        }
   
        chain.doFilter(req, res);
    }
}

2.實作 implements AuthenticationProvider
    我希望使用者部份功能需要帳號密碼才能使用,所以在這邊有判斷 Authentication是那一種類
    別,在實作 support時就要加上可允許的 token類別

public class CattonOAuthClientProvider implements AuthenticationProvider{
private static java.util.logging.Logger log1 = java.util.logging.Logger.getLogger("");

public CattonOAuthClientProvider() {
super();
}

public Authentication authenticate(Authentication authentication)    throws AuthenticationException {
log1.log(Level.WARNING,"authentication class type............. " +authentication.getClass().toString());

        if (authentication instanceof UsernamePasswordAuthenticationToken)  {
        ‧‧‧‧‧
                ‧‧‧‧
        log1.log(Level.WARNING, "...login by account password...................");
        System.out.println("...login by account password...................");
       
       
        }else if (authentication instanceof TestingAuthenticationToken ) {
        log1.log(Level.WARNING, "...anonymous..............");
       
        } else {
        log1.log(Level.WARNING, "faile to authenicate in provder..............");
        }
       
     
       return authentication;
    }

     public boolean supports(Class authentication) {
          return TestingAuthenticationToken.class.isAssignableFrom(authentication)
       || UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);

     }
}


 3.修改 spring-servlet.xml
 
    在 custom-filter after="EXCEPTION_TRANSLATION_FILTER" ref="oauth2ClientFilter" 之前加上
    custom-filter before="ANONYMOUS_FILTER" ref="authProcessingFilter"
 
    之後再加上
    bean class="com.catton.spring.security.AnoAuthenicationProcessingFilter" id="authProcessingFilter"
property name="authenticationManager" ref="defaultAuthenticationManager"

    bean id="authenticationProvider"   class="com.catton.spring.security.provider.CattonOAuthClientProvider"

    最後再修改 authentication-manager 設定為 authentication-provider ref="authenticationProvider" 即
    可



沒有留言:

張貼留言