forked from spring-projects/spring-security
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Issue: spring-projectsgh-5200
- Loading branch information
Showing
11 changed files
with
597 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
= OAuth 2.0 Resource Server Sample | ||
|
||
This sample demonstrates integrating Resource Server with a mock Authorization Server, though it can be modified to integrate | ||
with your favorite Authorization Server. | ||
|
||
With it, you can run the integration tests or run the application as a stand-alone service to explore how you can | ||
secure your own service with OAuth 2.0 Opaque Bearer Tokens using Spring Security. | ||
|
||
== 1. Running the tests | ||
|
||
To run the tests, do: | ||
|
||
```bash | ||
./gradlew integrationTest | ||
``` | ||
|
||
Or import the project into your IDE and run `OAuth2ResourceServerApplicationTests` from there. | ||
|
||
=== What is it doing? | ||
|
||
By default, the tests are pointing at a mock Authorization Server instance. | ||
|
||
The tests are configured with a set of hard-coded tokens originally obtained from the mock Authorization Server, | ||
and each makes a query to the Resource Server with their corresponding token. | ||
|
||
The Resource Server subsquently verifies with the Authorization Server and authorizes the request, returning the phrase | ||
|
||
```bash | ||
Hello, subject! | ||
``` | ||
|
||
where "subject" is the value of the `sub` field in the JWT returned by the Authorization Server. | ||
|
||
== 2. Running the app | ||
|
||
To run as a stand-alone application, do: | ||
|
||
```bash | ||
./gradlew bootRun | ||
``` | ||
|
||
Or import the project into your IDE and run `OAuth2ResourceServerApplication` from there. | ||
|
||
Once it is up, you can use the following token: | ||
|
||
```bash | ||
export TOKEN=00ed5855-1869-47a0-b0c9-0f3ce520aee7 | ||
``` | ||
|
||
And then make this request: | ||
|
||
```bash | ||
curl -H "Authorization: Bearer $TOKEN" localhost:8080 | ||
``` | ||
|
||
Which will respond with the phrase: | ||
|
||
```bash | ||
Hello, subject! | ||
``` | ||
|
||
where `subject` is the value of the `sub` field in the JWT returned by the Authorization Server. | ||
|
||
Or this: | ||
|
||
```bash | ||
export TOKEN=b43d1500-c405-4dc9-b9c9-6cfd966c34c9 | ||
|
||
curl -H "Authorization: Bearer $TOKEN" localhost:8080/message | ||
``` | ||
|
||
Will respond with: | ||
|
||
```bash | ||
secret message | ||
``` | ||
|
||
== 2. Testing against other Authorization Servers | ||
|
||
_In order to use this sample, your Authorization Server must support Opaque Tokens and the Introspection Endpoint. | ||
|
||
To change the sample to point at your Authorization Server, simply find this property in the `application.yml`: | ||
|
||
```yaml | ||
spring: | ||
security: | ||
oauth2: | ||
resourceserver: | ||
opaque: | ||
introspection-uri: ${mockwebserver.url}/introspect | ||
introspection-client-id: client | ||
introspection-client-secret: secret | ||
``` | ||
|
||
And change the property to your Authorization Server's Introspection endpoint, including its client id and secret: | ||
|
||
```yaml | ||
spring: | ||
security: | ||
oauth2: | ||
resourceserver: | ||
opaque: | ||
introspection-uri: ${mockwebserver.url}/introspect | ||
``` | ||
|
||
And then you can run the app the same as before: | ||
|
||
```bash | ||
./gradlew bootRun | ||
``` | ||
|
||
Make sure to obtain valid tokens from your Authorization Server in order to play with the sample Resource Server. | ||
To use the `/` endpoint, any valid token from your Authorization Server will do. | ||
To use the `/message` endpoint, the token should have the `message:read` scope. |
14 changes: 14 additions & 0 deletions
14
...uth2resourceserver-opaque/spring-security-samples-boot-oauth2resourceserver-opaque.gradle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
apply plugin: 'io.spring.convention.spring-sample-boot' | ||
|
||
dependencies { | ||
compile project(':spring-security-config') | ||
compile project(':spring-security-oauth2-jose') | ||
compile project(':spring-security-oauth2-resource-server') | ||
|
||
compile 'org.springframework.boot:spring-boot-starter-web' | ||
compile 'com.nimbusds:oauth2-oidc-sdk' | ||
compile 'com.squareup.okhttp3:mockwebserver' | ||
|
||
testCompile project(':spring-security-test') | ||
testCompile 'org.springframework.boot:spring-boot-starter-test' | ||
} |
101 changes: 101 additions & 0 deletions
101
...server-opaque/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* | ||
* Copyright 2002-2019 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package sample; | ||
|
||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.mock.web.MockHttpServletRequest; | ||
import org.springframework.test.context.ActiveProfiles; | ||
import org.springframework.test.context.junit4.SpringRunner; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
import org.springframework.test.web.servlet.request.RequestPostProcessor; | ||
|
||
import static org.hamcrest.Matchers.containsString; | ||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
||
/** | ||
* Integration tests for {@link OAuth2ResourceServerApplication} | ||
* | ||
* @author Josh Cummings | ||
*/ | ||
@RunWith(SpringRunner.class) | ||
@SpringBootTest | ||
@AutoConfigureMockMvc | ||
@ActiveProfiles("test") | ||
public class OAuth2ResourceServerApplicationITests { | ||
|
||
String noScopesToken = "00ed5855-1869-47a0-b0c9-0f3ce520aee7"; | ||
String messageReadToken = "b43d1500-c405-4dc9-b9c9-6cfd966c34c9"; | ||
|
||
@Autowired | ||
MockMvc mvc; | ||
|
||
@Test | ||
public void performWhenValidBearerTokenThenAllows() | ||
throws Exception { | ||
|
||
this.mvc.perform(get("/").with(bearerToken(this.noScopesToken))) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string(containsString("Hello, subject!"))); | ||
} | ||
|
||
// -- tests with scopes | ||
|
||
@Test | ||
public void performWhenValidBearerTokenThenScopedRequestsAlsoWork() | ||
throws Exception { | ||
|
||
this.mvc.perform(get("/message").with(bearerToken(this.messageReadToken))) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string(containsString("secret message"))); | ||
} | ||
|
||
@Test | ||
public void performWhenInsufficientlyScopedBearerTokenThenDeniesScopedMethodAccess() | ||
throws Exception { | ||
|
||
this.mvc.perform(get("/message").with(bearerToken(this.noScopesToken))) | ||
.andExpect(status().isForbidden()) | ||
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, | ||
containsString("Bearer error=\"insufficient_scope\""))); | ||
} | ||
|
||
private static class BearerTokenRequestPostProcessor implements RequestPostProcessor { | ||
private String token; | ||
|
||
public BearerTokenRequestPostProcessor(String token) { | ||
this.token = token; | ||
} | ||
|
||
@Override | ||
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { | ||
request.addHeader("Authorization", "Bearer " + this.token); | ||
return request; | ||
} | ||
} | ||
|
||
private static BearerTokenRequestPostProcessor bearerToken(String token) { | ||
return new BearerTokenRequestPostProcessor(token); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
...que/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* Copyright 2002-2019 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.boot.env; | ||
|
||
import org.springframework.beans.factory.DisposableBean; | ||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.core.env.ConfigurableEnvironment; | ||
|
||
/** | ||
* @author Rob Winch | ||
*/ | ||
public class MockWebServerEnvironmentPostProcessor | ||
implements EnvironmentPostProcessor, DisposableBean { | ||
|
||
private final MockWebServerPropertySource propertySource = new MockWebServerPropertySource(); | ||
|
||
@Override | ||
public void postProcessEnvironment(ConfigurableEnvironment environment, | ||
SpringApplication application) { | ||
environment.getPropertySources().addFirst(this.propertySource); | ||
} | ||
|
||
@Override | ||
public void destroy() throws Exception { | ||
this.propertySource.destroy(); | ||
} | ||
} |
Oops, something went wrong.