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
2019年1月28日 星期一
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" 即
可
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.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" 的設定
程式下載: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新增
再來就是 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();
}
實作畫面
訂閱:
文章 (Atom)