顯示具有 spring 標籤的文章。 顯示所有文章
顯示具有 spring 標籤的文章。 顯示所有文章

2019年1月28日 星期一

Spring Boot

Spring Boot出來很久了,但因為工作上沒有使用到,所以一直沒有學習,最近又想了解 OAuth2才知道它的存在,短暫的學習心得,發現它跟 .Net Core有類似,用大量 annotation, dependency injection,還有以前的 xml設定檔,現在都用 class替代了,有興趣的人可以參考如下網站

Spring Boot 基础
Adding Classpath Dependencies
Building microservices with Netflix OSS, Apache Kafka and Spring Boot – Part 1: Service registry and Config server
Deploy a Spring Boot MicroService with Netflix OSS stack in Docker Container

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" 即
    可



2012年11月6日 星期二

spring security oauth 1 client logout


這樣應該就可以作 logout的動作

OAuthSecurityContext context = OAuthSecurityContextHolder.getContext();
       
 Map accessTokens = context.getAccessTokens();
  accessTokens.remove(resource id);
  session.removeAttribute("OAUTH_TOKEN#"+resourceid);
     
 


參考文件
http://forum.springsource.org/showthread.php?104433-Revoked-expired-access-token-in-oauth1

2012年8月27日 星期一

OAuth for Spring Security 應用實作

參考來源:https://github.com/SpringSource/spring-security-oauth/wiki/tutorial
程式下載:https://github.com/SpringSource/spring-security-oauth 網頁下面有文字說明如何使用 maven將 source code下載回來。

目前 tutorial 有實作 OAuth1, OAuth2 的Server 和 Client, Client 可以下載 Server 的圖片。 而我的目的就是可以建立一個公司內部認證網站(OAuth 是用來作授權用的),使用者在連其它公司自製網站時可以連來這個網站使用 Notes or AD, Oracle ERP 的帳號作登入,當帳號、密碼正確時就可以允許 oauth client 存取 登入使用者的工號、部門、 email等。

修改部份:
首先我選擇的是拿 OAuth2的範列來改,Server  的 source code 代號為 Sparklr2,Client 的代號為 Tonr2。

因為要讓使用者可以用Notes or AD, Oracle ERP 的帳號作登入,所以要先改 OAuth2 Server 的部份,目前 spring security 選擇 authentication的方式有兩種,一種是 AuthenticationProvider ,一種是UserService,我選擇的是AuthenticationProvider ,所以要實作一個 class implements org.springframework.security.authentication.AuthenticationProvider 並實作兩個 method

1.public Authentication authenticate(Authentication authentication)   ==>讓我可以用Notes or AD, Oracle ERP 的帳號、宓碼登入後檢查是否正確。

2. public boolean supports(Class authentication) {
         return authentication.equals(UsernamePasswordAuthenticationToken.class);

     }

等這個 provider實作好之後,就要在 WEB-INF\spring-servlet.xml 內加上設定,這樣就可以完成認證的功能了。





再來就是分享員工資訊的程式了, 可以實作自己的 controller,參考原程式分享 photoID的 service : PhotoController, PhotoServiceImpl,PhotoService
記得WEB-INF\spring-servlet.xml 也要將相關的 tag 加上。

而 Client 的程式也請參考原程式如何存取 photoID
等 server , client 的程式都實作好之後就可以放到 tomcat 上了。 目前實作好之後才發現 Client 要先自己認證完成,才可以去 Server再去作認證一次,才可以存取我的員工資訊,但我想的是 Client 本身不用有認證的程序,直接到  server 作認證後存取資料。上網找了一下資訊,發現好像沒有人分享怎麼設定 OAuth2才可以達到我的要求,所以我又拿了 OAuth1的 source code改了一次。

OAuth1 跟 OAuth2 設定上有一點不一樣,除了WEB-INF\spring-servlet.xml之外,又多了一個檔案 applicationContext.xml,也是 spring 標準設定檔。
這邊也是實作我自己的 AuthenticationProvider ,但是在設定上就不是在 spring-servlet.xml新增 的資訊了,而是要放在 applicationContext.xml 而且 bean 要改為 beans:bean 這樣才可以。 其它 controller or  service的程式才在spring-servlet.xml 註冊。
再來就是 oauth:consumer-details-service id="consumerDetails" 的設定 


這邊就可增加自己   oauth:consumer

實作分享員工資訊的程式也跟 OAuth2實作差不多,設定上 OAuth1 OAuth2會有差異,只要參考原程式存取 photoID怎麼寫和怎麼設定應該就沒什麼大問題了。 


最後我想測試用 asp.net 也可以存取我的 OAuth1實作出來的 server員工資訊,這一次我採用

DotNetOpenAuth  http://www.dotnetopenauth.net/ 

實作自己的 service comsumer

public static readonly ServiceProviderDescription ServiceDescription = new ServiceProviderDescription {
            RequestTokenEndpoint = new MessageReceivingEndpoint("http://ip:port/OAuth1Server/oauth/request_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
            UserAuthorizationEndpoint = new MessageReceivingEndpoint("http://ip:port/OAuth1Server /oauth/confirm_access", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
            AccessTokenEndpoint = new MessageReceivingEndpoint("http:// ip:port/OAuth1Server /oauth/access_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
};

/// The URI to get the data on the user's home page.
///
        private static readonly MessageReceivingEndpoint cattonEmpInfoEndpoint = new MessageReceivingEndpoint("http:// ip:port/OAuth1Server/service?format=json", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest);


private static InMemoryTokenManager ShortTermUserSessionTokenManager {
get {
var store = HttpContext.Current.Session;
var tokenManager = (InMemoryTokenManager)store["CattonOAuth1SessionTokenManager"];
if (tokenManager == null) {
                    string consumerKey = ConfigurationManager.AppSettings["CattonOAuthConsumerKey"];
                    string consumerSecret = ConfigurationManager.AppSettings["CattonOAuthConsumerSecret"];
if (IsTwitterConsumerConfigured) {
tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
                        store["CattonOAuth1SessionTokenManager"] = tokenManager;
} else {
throw new InvalidOperationException("No Catton OAuth consumer key and secret could be found in web.config AppSettings.");
}
}

return tokenManager;
}
}

public static string GetUserInfo(ConsumerBase cattonOAuthCB, string accessToken) {
            IncomingWebResponse response = cattonOAuthCB.PrepareAuthorizedRequestAndSend(cattonEmpInfoEndpoint, accessToken);
          
            return  response.GetResponseReader().ReadToEnd();

}

實作畫面