oauth2 token database access

This commit is contained in:
liquidjoo
2019-05-17 19:12:03 +09:00
parent f200527833
commit b2e2a518b2
14 changed files with 327 additions and 27 deletions

View File

@@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
@@ -19,8 +20,11 @@ import org.springframework.security.oauth2.provider.code.AuthorizationCodeServic
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import javax.sql.DataSource;
import java.security.KeyPair;
@Configuration
@EnableAuthorizationServer
@@ -54,9 +58,9 @@ public class OAuth2SsoServerConfig extends AuthorizationServerConfigurerAdapter
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
// auth server에 대한 설정
// security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
// properties 로 해결 가능
super.configure(security);
// super.configure(security);
}
@Override
@@ -73,12 +77,17 @@ public class OAuth2SsoServerConfig extends AuthorizationServerConfigurerAdapter
.approvalStore(approvalStore)
// code service
.authorizationCodeServices(authorizationCodeServices);
// .accessTokenConverter(jwtAccessTokenConverter());
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// client 에 대한 설정
clients.withClientDetails(clientDetailsService);
// clients.inMemory().withClient("system1").secret("1234")
// .authorizedGrantTypes("authorization_code", "refresh_token","password")
// .scopes("read");
}
@Bean
@@ -101,4 +110,13 @@ public class OAuth2SsoServerConfig extends AuthorizationServerConfigurerAdapter
public ApprovalStore jdbcApprovalStore(DataSource dataSource) {
return new JdbcApprovalStore(dataSource);
}
// @Bean
// public JwtAccessTokenConverter jwtAccessTokenConverter() {
// JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
// converter.setSigningKey("abc");
//// KeyPair keyPair = new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "foobar".toCharArray()).getKeyPair("test");
//// converter.setKeyPair(keyPair);
// return converter;
// }
}

View File

@@ -0,0 +1,27 @@
package io.bluemoon.authorizationserver.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.web.filter.ForwardedHeaderFilter;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@EnableWebSecurity
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
FilterRegistrationBean forwardedHeaderFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new ForwardedHeaderFilter());
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegistrationBean;
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/oauth/confirm_access").setViewName("authorize");
}
}

View File

@@ -41,20 +41,12 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").permitAll()
http.formLogin().loginPage("/login").permitAll()
.and()
.logout()
.permitAll();
.authorizeRequests().anyRequest().authenticated();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//
auth
.inMemoryAuthentication()
.withUser("user1").password("1234").roles("USER");
}
/**
* authentication Object managing

View File

@@ -1,4 +1,6 @@
server.port=8081
server.servlet.context-path=/mk-auth
server.use-forward-headers=false
security.oauth2.authorization.check-token-access=isAuthenticated()

View File

@@ -0,0 +1,27 @@
<html>
<head>
</head>
<body>
<div class="container">
<h2>Please Confirm</h2>
<p>
Do you authorize "${authorizationRequest.clientId}" at "${authorizationRequest.redirectUri}" to access your
protected resources
with scope ${authorizationRequest.scope?join(", ")}.
</p>
<form id="confirmationForm" name="confirmationForm"
action="../oauth/authorize" method="post">
<input name="user_oauth_approval" value="true" type="hidden"/>
<input type="hidden" id="csrf_token" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<button class="btn btn-primary" type="submit">Approve</button>
</form>
<form id="denyForm" name="confirmationForm"
action="../oauth/authorize" method="post">
<input name="user_oauth_approval" value="false" type="hidden"/>
<input type="hidden" id="csrf_token" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<button class="btn btn-primary" type="submit">Deny</button>
</form>
</div>
</body>
</html>

View File

@@ -0,0 +1,20 @@
<html>
<head>
</head>
<body>
<div class="container">
<form role="form" action="login" method="post">
<div class="form-group">
<label for="username">Username:</label>
<input type="text" class="form-control" id="username" name="username"/>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" class="form-control" id="password" name="password"/>
</div>
<input type="hidden" id="csrf_token" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>

View File

@@ -1,5 +1,6 @@
#Fri May 17 17:34:15 KST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip

View File

@@ -2,7 +2,23 @@ package io.bluemoon.gatewayzuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoRestTemplateCustomizer;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.security.oauth2.client.token.AccessTokenProviderChain;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.implicit.ImplicitAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordAccessTokenProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@EnableZuulProxy
@SpringBootApplication
public class GatewayZuulApplication {
@@ -10,4 +26,18 @@ public class GatewayZuulApplication {
SpringApplication.run(GatewayZuulApplication.class, args);
}
// @Bean
// UserInfoRestTemplateCustomizer userInfoRestTemplateCustomizer(LoadBalancerInterceptor loadBalancerInterceptor) {
// return template -> {
// List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
// interceptors.add(loadBalancerInterceptor);
// AccessTokenProviderChain accessTokenProviderChain = Stream
// .of(new AuthorizationCodeAccessTokenProvider(), new ImplicitAccessTokenProvider(),
// new ResourceOwnerPasswordAccessTokenProvider(), new ClientCredentialsAccessTokenProvider())
// .peek(tp -> tp.setInterceptors(interceptors))
// .collect(Collectors.collectingAndThen(Collectors.toList(), AccessTokenProviderChain::new));
// template.setAccessTokenProvider(accessTokenProviderChain);
// };
// }
}

View File

@@ -1,28 +1,112 @@
package io.bluemoon.gatewayzuul.config;
import io.bluemoon.gatewayzuul.filter.DynamicOauth2ClientContextFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;
@Configuration
@EnableOAuth2Sso
@EnableResourceServer
@Order(value = 0)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user1").password("1234").roles("USER");
}
// @Bean
// @Primary
// public OAuth2ClientContextFilter dynamicOauth2ClientContextFilter() {
// return new DynamicOauth2ClientContextFilter();
// }
@Override
protected void configure(HttpSecurity http) throws Exception {
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**", "/login").permitAll()
.antMatchers("/mk-auth/**", "/login").permitAll().anyRequest().authenticated()
.and()
.csrf().requireCsrfProtectionMatcher(csrfRequestMatcher()).csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.logout().permitAll()
.logoutSuccessUrl("/");
}
private RequestMatcher csrfRequestMatcher() {
return new RequestMatcher() {
private final Pattern allowedMethods = Pattern.compile("^(GET|HEAD|OPTIONS|TRACE)$");
// Disable CSFR protection on the following urls:
private final AntPathRequestMatcher[] requestMatchers = { new AntPathRequestMatcher("/mk-auth/**") };
@Override
public boolean matches(HttpServletRequest request) {
if (allowedMethods.matcher(request.getMethod()).matches()) {
return false;
}
for (AntPathRequestMatcher matcher : requestMatchers) {
if (matcher.matches(request)) {
return false;
}
}
return true;
}
};
}
private static Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = new Cookie("XSRF-TOKEN", csrf.getToken());
cookie.setPath("/");
cookie.setSecure(true);
response.addCookie(cookie);
}
filterChain.doFilter(request, response);
}
};
}
private static CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}

View File

@@ -0,0 +1,45 @@
package io.bluemoon.gatewayzuul.filter;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
public class DynamicOauth2ClientContextFilter extends OAuth2ClientContextFilter {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
protected void redirectUser(UserRedirectRequiredException e, HttpServletRequest request, HttpServletResponse response) throws IOException {
String redirectUri = e.getRedirectUri();
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(redirectUri);
Map<String, String > requestParams = e.getRequestParams();
for (Map.Entry<String ,String> param : requestParams.entrySet()) {
builder.queryParam(param.getKey(), param.getValue());
}
if (e.getStateKey() != null) {
builder.queryParam("state", e.getStateKey());
}
String url = getBaseUrl(request) + builder.build().encode().toUriString();
this.redirectStrategy.sendRedirect(request, response, url);
}
private String getBaseUrl(HttpServletRequest request) {
StringBuffer url = request.getRequestURL();
return url.substring(0, url.length() - request.getRequestURI().length() + request.getContextPath().length());
}
@Override
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
}

View File

@@ -1,19 +1,37 @@
server.port=8765
zuul.routes.mk2-service.path=/service/**
zuul.routes.mk2-service.url=http://127.0.0.1:8082
zuul.routes.mk2-oauth.path=/mk-auth/**
zuul.routes.mk2-oauth.url=http://127.0.0.1:8081
zuul.routes.mk2-oauth.sensitive-headers=Authorization
#zuul.routes.mk2-oauth.path=/mk2auth/**
zuul.routes.mk2-oauth.path=/**
zuul.routes.mk2-oauth.strip-prefix=false
zuul.add-proxy-headers=true
security.oauth2.sso.login-path=/mk2/login
security.oauth2.sso.login-path=/login
security.oauth2.client.access-token-uri=http://mk2-oauth/oauth/token
security.oauth2.client.user-authorization-uri=/oauth/authorize
security.oauth2.client.access-token-uri=http://127.0.0.1:8081/mk-auth/oauth/token
security.oauth2.client.user-authorization-uri=http://127.0.0.1:8081/mk-auth/oauth/authorize
security.oauth2.resource.token-info-uri=http://127.0.0.1:8081/mk-auth/oauth/check_token
security.oauth2.client.client-id=system1
security.oauth2.client.client-secret=1234
spring.security.user.name=user1
spring.security.user.password=1234
security.oauth2.resource.token-info-uri=http://mk2-oauth/check_token
#security.oauth2.resource.jwt.key-value="abc"
#security.oauth2.resource.id=read
#security.oauth2.resource.service-id=${PREFIX:}resource
management.endpoints.web.exposure.include=routes, health, filter
management.endpoint.routes.enabled=true
management.endpoint.filters.enabled=true

View File

@@ -26,7 +26,6 @@ ext {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-oauth2'
implementation 'org.springframework.cloud:spring-cloud-starter-security'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

View File

@@ -2,7 +2,16 @@ package io.bluemoon.testservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.security.Principal;
@EnableResourceServer
@SpringBootApplication
public class TestServiceApplication {
@@ -10,4 +19,28 @@ public class TestServiceApplication {
SpringApplication.run(TestServiceApplication.class, args);
}
@Controller
@RequestMapping("/")
public static class TestController{
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public String helloMk2(Principal principal) {
return principal == null ? "hello anonymous" : "heelo" + principal.getName();
}
@PreAuthorize("#oauth2.hasScope('read') and hasRole('ROLE_USER')")
@RequestMapping(value = "secret", method = RequestMethod.GET)
@ResponseBody
public String helloMk2Secret(Principal principal) {
return principal == null ? "hello anonymous" : "heelo" + principal.getName();
}
@RequestMapping(method = RequestMethod.GET, value = "test")
@ResponseBody
public String test() {
return "test";
}
}
}

View File

@@ -1 +1,5 @@
server.port=8082
security.oauth2.resource.token-info-uri=http://127.0.0.1:8081/mk-auth/oauth/check_token