Skip to content

Commit 635a483

Browse files
committed
JAVA-15697 Move oauth-microservices repo code to spring-security-oauth repo
1 parent 4d08463 commit 635a483

File tree

83 files changed

+2899
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+2899
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
2+
# POC for an OAuth2-based Architecture running behind an API Gateway
3+
4+
## Overview
5+
Here are all the individual services:
6+
- `service-registry-1` - the Eureka-based service registry
7+
- `api-gateway-zuul-1` - the Zuul-based API Gateway
8+
- `authorization-server-1` - the Authoization Server
9+
- `resource-server-mvc-1` - the Resource Server
10+
11+
Note that these are all implemented using Spring Boot 1.x
12+
13+
14+
15+
## Ops
16+
When starting up the services, the sequence should be - `service-registry-1` first, everything else after.
17+
18+
19+
20+
## Run
21+
Once everything starts up, try to access the Resource Server, through the Gateway:
22+
`http://localhost:8765/resource-server-mvc-1`
23+
24+
Or, if you're authenticating with an admin:
25+
`http://localhost:8765/resource-server-mvc-1/secret`
26+
27+
You'll be redirected to the Authorization Server to authenticate.
28+
Use the following credentials: `user`/`password` or `admin`/`admin`.
29+
And approve the authorization for the `fooScope` OAuth scope.
30+
31+
32+
33+
## High-Level Flow
34+
35+
Here's what the typical flow looks like:
36+
37+
```
38+
Browser API Gateway (APIG) Authorization Server (AS)
39+
│ APIG/resource-server-new │ │
40+
├────────────────────────────────────────>│ │
41+
│ Location:http://APIG/login │ │
42+
│<────────────────────────────────────────│ │
43+
│ http://APIG/login │ │
44+
├────────────────────────────────────────>│ │
45+
│ Location:http://APIG/AS/oauth/authorize │ │
46+
│<────────────────────────────────────────│ │
47+
│ http://APIG/AS/oauth/authorize │ │
48+
├────────────────────────────────────────>│ │
49+
│ │ /AS/oauth/authorize │
50+
│ ├─────────────────────────────────>│
51+
│ │ ├──┐
52+
│ │ │ │ Not authorized
53+
│ │ │<─┘
54+
│ │ Location:http://APIG/AS/login │
55+
│ │<─────────────────────────────────┤
56+
│ Location:http://APIG/AS/login │ │
57+
│<────────────────────────────────────────│ │
58+
│ http://APIGAS/AS/login │ │
59+
├────────────────────────────────────────>│ │
60+
│ │ /AS/login │
61+
│ ├─────────────────────────────────>│
62+
│ │ LOGIN FORM │
63+
│ │<─────────────────────────────────┤
64+
│ LOGIN FORM │ │
65+
│<────────────────────────────────────────┤ │
66+
```
67+
68+
- note that the Authorization Server is internal and never communicates with the outside world
69+
70+
71+
72+
## Implementation Notes
73+
74+
### Oauth2ClientContextFilterWithPath
75+
The custom OAuth2ClientContextFilter now supports URIs (paths), beyond just full URLs.
76+
We need this path support so that we're able to use it via `security.oauth2.client.userAuthorizationUri` in Zuul, to redirect to Zuul itself.
77+
Alternatively, we could hardcode this to: `http://localhost:${server.port}/authorization-server-1/oauth/authorize` (not ideal)
78+
79+
80+
### `zuul.authorization-server-1.sensitiveHeaders`
81+
We need the Cookie to be passed through from the Authorization Server
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<artifactId>api-gateway-zuul-1</artifactId>
7+
<packaging>jar</packaging>
8+
9+
<name>api-gateway-zuul-1</name>
10+
11+
<parent>
12+
<groupId>com.baeldung</groupId>
13+
<artifactId>spring-security-oauth-1</artifactId>
14+
<version>0.0.6</version>
15+
</parent>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>org.springframework.cloud</groupId>
20+
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
21+
</dependency>
22+
<dependency>
23+
<groupId>org.springframework.cloud</groupId>
24+
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
25+
</dependency>
26+
27+
<dependency>
28+
<groupId>org.springframework.cloud</groupId>
29+
<artifactId>spring-cloud-starter-oauth2</artifactId>
30+
</dependency>
31+
<dependency>
32+
<groupId>org.springframework.cloud</groupId>
33+
<artifactId>spring-cloud-starter-security</artifactId>
34+
</dependency>
35+
36+
<dependency>
37+
<groupId>org.springframework.boot</groupId>
38+
<artifactId>spring-boot-starter-test</artifactId>
39+
<scope>test</scope>
40+
</dependency>
41+
</dependencies>
42+
43+
<build>
44+
<plugins>
45+
<plugin>
46+
<groupId>org.springframework.boot</groupId>
47+
<artifactId>spring-boot-maven-plugin</artifactId>
48+
<executions>
49+
<execution>
50+
<goals>
51+
<goal>repackage</goal>
52+
</goals>
53+
</execution>
54+
</executions>
55+
</plugin>
56+
</plugins>
57+
</build>
58+
59+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.baeldung;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6+
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
7+
8+
@SpringBootApplication
9+
@EnableZuulProxy
10+
@EnableDiscoveryClient
11+
public class ApiGatewayApplication {
12+
13+
public static void main(String[] args) {
14+
SpringApplication.run(ApiGatewayApplication.class, args);
15+
}
16+
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.baeldung.security;
2+
3+
import java.io.IOException;
4+
import java.util.Map;
5+
6+
import javax.servlet.http.HttpServletRequest;
7+
import javax.servlet.http.HttpServletResponse;
8+
9+
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
10+
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
11+
import org.springframework.security.web.DefaultRedirectStrategy;
12+
import org.springframework.security.web.RedirectStrategy;
13+
import org.springframework.web.util.UriComponentsBuilder;
14+
15+
class Oauth2ClientContextFilterWithPath extends OAuth2ClientContextFilter {
16+
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
17+
18+
@Override
19+
protected void redirectUser(UserRedirectRequiredException e, HttpServletRequest request, HttpServletResponse response) throws IOException {
20+
final String redirectUri = e.getRedirectUri();
21+
final UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(redirectUri);
22+
final Map<String, String> requestParams = e.getRequestParams();
23+
for (Map.Entry<String, String> param : requestParams.entrySet()) {
24+
builder.queryParam(param.getKey(), param.getValue());
25+
}
26+
27+
if (e.getStateKey() != null) {
28+
builder.queryParam("state", e.getStateKey());
29+
}
30+
31+
String url = getBaseUrl(request) + builder.build().encode().toUriString();
32+
this.redirectStrategy.sendRedirect(request, response, url);
33+
}
34+
35+
@Override
36+
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
37+
this.redirectStrategy = redirectStrategy;
38+
}
39+
40+
private String getBaseUrl(HttpServletRequest request) {
41+
StringBuffer url = request.getRequestURL();
42+
return url.substring(0, url.length() - request.getRequestURI().length() + request.getContextPath().length());
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.baeldung.security;
2+
3+
import org.springframework.beans.factory.annotation.Autowired;
4+
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.context.annotation.Primary;
8+
import org.springframework.core.annotation.Order;
9+
import org.springframework.security.authentication.AuthenticationManager;
10+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
11+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
12+
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
13+
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
14+
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager;
15+
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter;
16+
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
17+
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
18+
19+
@Configuration
20+
@EnableOAuth2Sso
21+
@EnableResourceServer
22+
@Order(value = 0)
23+
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
24+
25+
@Autowired
26+
private ResourceServerTokenServices resourceServerTokenServices;
27+
28+
@Bean
29+
@Primary
30+
public OAuth2ClientContextFilter oauth2ClientContextFilterWithPath() {
31+
return new Oauth2ClientContextFilterWithPath();
32+
}
33+
34+
@Override
35+
public void configure(HttpSecurity http) throws Exception { // @formatter:off
36+
http.csrf().disable()
37+
.authorizeRequests()
38+
.antMatchers("/authorization-server-1/**", "/login").permitAll()
39+
.anyRequest().authenticated()
40+
.and().addFilterAfter(oAuth2AuthenticationProcessingFilter(), AbstractPreAuthenticatedProcessingFilter.class)
41+
.logout().permitAll().logoutSuccessUrl("/");
42+
} // @formatter:on
43+
44+
private OAuth2AuthenticationProcessingFilter oAuth2AuthenticationProcessingFilter() {
45+
OAuth2AuthenticationProcessingFilter oAuth2AuthenticationProcessingFilter = new OAuth2AuthenticationProcessingFilter();
46+
oAuth2AuthenticationProcessingFilter.setAuthenticationManager(oauthAuthenticationManager());
47+
oAuth2AuthenticationProcessingFilter.setStateless(false);
48+
49+
return oAuth2AuthenticationProcessingFilter;
50+
}
51+
52+
private AuthenticationManager oauthAuthenticationManager() {
53+
OAuth2AuthenticationManager oAuth2AuthenticationManager = new OAuth2AuthenticationManager();
54+
oAuth2AuthenticationManager.setResourceId("apigateway");
55+
oAuth2AuthenticationManager.setTokenServices(resourceServerTokenServices);
56+
oAuth2AuthenticationManager.setClientDetailsService(null);
57+
58+
return oAuth2AuthenticationManager;
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
spring:
2+
aop:
3+
proxyTargetClass: true
4+
application:
5+
name: api-gateway-zuul-1
6+
7+
server:
8+
port: 8765
9+
10+
eureka:
11+
instance:
12+
hostname: localhost
13+
port: 8761
14+
client:
15+
serviceUrl:
16+
defaultZone: http://${eureka.instance.hostname}:${eureka.instance.port}/eureka/
17+
18+
zuul:
19+
routes:
20+
resource-server-mvc-1: /resource-server-mvc-1/**
21+
authorization-server-1:
22+
sensitiveHeaders: Authorization
23+
path: /authorization-server-1/**
24+
stripPrefix: false
25+
add-proxy-headers: true
26+
27+
security:
28+
basic:
29+
enabled: false
30+
oauth2:
31+
sso:
32+
loginPath: /login
33+
client:
34+
accessTokenUri: http://localhost:8769/authorization-server-1/oauth/token
35+
userAuthorizationUri: /authorization-server-1/oauth/authorize
36+
clientId: fooClient
37+
clientSecret: fooSecret
38+
resource:
39+
jwt:
40+
keyValue: "abc"
41+
id: fooScope
42+
serviceId: ${PREFIX:}resource
43+
44+
logging:
45+
level.org.springframework.security: DEBUG
46+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.baeldung;
2+
3+
import org.junit.Test;
4+
import org.junit.runner.RunWith;
5+
import org.springframework.boot.autoconfigure.web.ServerProperties;
6+
import org.springframework.boot.test.context.SpringBootTest;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.context.annotation.Configuration;
9+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
10+
11+
import com.baeldung.ApiGatewayApplication;
12+
13+
@RunWith(SpringJUnit4ClassRunner.class)
14+
@SpringBootTest(classes = ApiGatewayApplication.class)
15+
public class ApiGatewayApplicationTests {
16+
17+
@Configuration
18+
public static class ByPassConfiguration {
19+
@Bean
20+
public ServerProperties serverProperties() {
21+
return new ServerProperties();
22+
}
23+
}
24+
25+
@Test
26+
public void contextLoads() {
27+
}
28+
29+
}

0 commit comments

Comments
 (0)