Skip to content

Commit d76af38

Browse files
authored
chore: fix stale README run instructions and rename the container variable (#184)
1 parent b5778f1 commit d76af38

2 files changed

Lines changed: 37 additions & 42 deletions

File tree

README.md

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
This is an _unofficial_ reference implementation of the User Login and Consent flow of an
44
[Ory Hydra](https://github.com/ory) OAuth 2.0 server written in Java with SpringBoot. This project demos some
5-
key features/flows/integrations and the of OAuth 2.0 Authorization Code Grant flow. It is mean to be a foundation for
6-
production implementations, but it is not an exhaustive implementation nor is guaranteed to be secure, bug free, fully
7-
tested, or production ready.
5+
key features, flows, and integrations of the OAuth 2.0 Authorization Code Grant flow. It is meant to be a foundation
6+
for production implementations, but it is not an exhaustive implementation nor is it guaranteed to be secure, bug
7+
free, fully tested, or production ready.
88

99
Similar reference implementations can be found on
1010
the [Getting Started](https://www.ory.sh/docs/getting-started/overview)
@@ -65,19 +65,19 @@ The functional tests for this project run along all other tests with the standar
6565
```
6666

6767
The functional tests are unique because there is practically no mocking. This makes for a slightly more complicated
68-
setup, but it allows us to reproduce scenarios in a context very similar to what would be seen in production, all they
68+
setup, but it allows us to reproduce scenarios in a context very similar to what would be seen in production, all the
6969
way from interacting with the UI back to Ory Hydra.
7070

7171
1. Using `@SpringBootTest`, the application is started on a random port. Note that the application also configures two
7272
extra controllers to help facilitate testing.
73-
2. A Playwright browser instance is created (this will be shared for all tests).
74-
3. Before each test, a new Test Container instance of Ory Hydra is started. This instance of Ory Hydra is running with
75-
an in memory database.
76-
4. A Hydra OAuth client is created.
73+
2. A Playwright browser instance is created (shared by all tests).
74+
3. A single Test Container instance of Ory Hydra is started and shared by every test in the class. It runs with an
75+
in-container SQLite database.
76+
4. Before each test, a unique Hydra OAuth client is created. Hydra remembers consent per subject and client, so a
77+
fresh client per test keeps tests isolated on the shared container.
7778
5. The Playwright browser loads the `/oauth2/auth` endpoint with the client's information.
7879
6. The Playwright api is used to interact with the UI just as a user would do.
7980
7. Optionally, the code may be exchanged for the token response.
80-
8. Repeat from Step 3 for each test.
8181

8282
The extra controllers created are not ideal but are useful for testing. One of them is a `ForwardingController` which
8383
helps work around some networking challenges with a circular dependency in configuration between the application and Ory
@@ -89,15 +89,8 @@ provides a hook for the client call back. This allows us to verify that Hydra ac
8989
and provides us access to the `code` value so that it can be exchanged for the token response.
9090

9191
Since the token flow of OAuth is inherently UI driven, it is imperative that the UI be the driver for the tests. To aid
92-
with this the `Playwright` framework is used. Allows us to use a headless driver to load the UI and use HTML selectors
93-
to interact with the loaded page just like a human would.
94-
95-
Due to the overhead of Test Containers, the tests are a bit slow and there is likely some optimization that could be
96-
made so that the Ory Hydra containers are re-used across each test rather than recreated for each test.
97-
98-
#### Playwright
99-
100-
#### Test Containers
92+
with this the `Playwright` framework is used. It allows us to use a headless driver to load the UI and use HTML
93+
selectors to interact with the loaded page just like a human would.
10194

10295
### Running With Local Ory Hydra
10396

@@ -109,18 +102,22 @@ Note: All steps require Docker and some require `jq`. All commands should run re
109102
#### Start Hydra And The Reference App
110103

111104
```
112-
# Pull Hydra
113-
docker pull oryd/hydra:v2.0.2
114-
115-
# Use the same docker-compose file used by the functional tests to start Hydra
116-
# with an in memory database and run the migration sccripts.
117-
docker-compose -f ./reference-app/src/test/resources/docker-compose.yml up --build
105+
# Start Hydra with an in-container SQLite database, running the migrations first —
106+
# the same single-container setup the functional tests get from testcontainers-ory-hydra.
107+
docker run --rm --name hydra \
108+
-p 4444:4444 -p 4445:4445 \
109+
-e DSN="sqlite:///tmp/db.sqlite?_fk=true" \
110+
-e SECRETS_SYSTEM=local-dev-secret \
111+
-e URLS_LOGIN=http://localhost:8080/login \
112+
-e URLS_CONSENT=http://localhost:8080/consent \
113+
--entrypoint sh oryd/hydra:v25.4.0 \
114+
-c "hydra migrate sql -e --yes && hydra serve all --dev"
118115
119116
# At this point Hydra urls such as http://localhost:4445/admin/clients should be up and running.
120117
121118
# Open a new terminal...
122119
123-
# Start the Spring app.
120+
# Start the Spring app.
124121
./gradlew bootRun
125122
126123
# At this point the reference app pages such as localhost:8080/index.html should load.
@@ -138,7 +135,7 @@ Otherwise, follow these instructions to create a client and test it by going thr
138135

139136
```
140137
# Create a client. Uses the Hydra container to access the Hydra CLI.
141-
hydra_client=$(docker-compose -f ./reference-app/src/test/resources/docker-compose.yml exec hydra \
138+
hydra_client=$(docker exec hydra \
142139
hydra create client \
143140
--endpoint http://127.0.0.1:4445 \
144141
--grant-type authorization_code,refresh_token \
@@ -165,15 +162,15 @@ curl -X PATCH \
165162
oauth_endpoint="http://localhost:4444/oauth2/auth?\
166163
client_id=${hydra_client_id}&\
167164
response_type=code&\
168-
redirect_uri=${client_redirect_uri_0}&\
165+
redirect_uri=${hydra_client_redirect_uri_0}&\
169166
scope=openid+offline&\
170167
state=123456789"
171168
172169
# Print the endpoint.
173170
echo $oauth_endpoint
174171
175172
# Click on the printed endpoint (or paste it into a browser).
176-
# Complete the OAuth flow (by default the hard coded crentials are username: foo@bar.com password: password).
173+
# Complete the OAuth flow (by default the hard coded credentials are username: foo@bar.com password: password).
177174
178175
# replace '...' with the `code` query param in the call back.
179176
code=...
@@ -185,7 +182,7 @@ curl -X POST \
185182
-d "grant_type=authorization_code" \
186183
-d "code=${code}" \
187184
-d "redirect_uri=http%3A%2F%2F127.0.0.1%3A5555%2Fcallback" \
188-
-d "client_id=${code_client_id}" \
185+
-d "client_id=${hydra_client_id}" \
189186
http://127.0.0.1:4444/oauth2/token
190187
```
191188

@@ -242,7 +239,7 @@ sequenceDiagram
242239
When the code is exchanged the response contains a `id_token` key with a JWT string. Additional information about that
243240
token can be found [here](https://openid.net/specs/openid-connect-core-1_0.html).
244241

245-
You can also see how this demo includes how to include "custom" claims that are not part of the OIDC spect.
242+
This demo also shows how to include "custom" claims that are not part of the OIDC spec.
246243
Look in the JWT for the value `example custom claim value`.
247244

248245
Here is an example JWT json:
@@ -365,4 +362,3 @@ instead, use a Gradle composite build:
365362
- [ ] Log out
366363
- [ ] Add example with Ory Cloud
367364

368-
## Additional Notes

reference-app/src/test/java/com/ardetrick/oryhydrareference/OryHydraReferenceApplicationFunctionalTests.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public class OryHydraReferenceApplicationFunctionalTests {
6363

6464
@LocalServerPort int springBootAppPort;
6565

66-
OryHydraContainer dockerComposeEnvironment;
66+
OryHydraContainer oryHydraContainer;
6767

6868
String clientId;
6969
String clientSecret;
@@ -96,27 +96,27 @@ void startTestEnvironment() {
9696
// One Hydra container serves every test in this class — containers are the expensive
9797
// resource. Test isolation is preserved by registering a unique OAuth2 client per test
9898
// instead (see registerTestClient).
99-
dockerComposeEnvironment =
99+
oryHydraContainer =
100100
OryHydraContainer.builder()
101101
.urlsLogin("http://localhost:" + springBootAppPort + "/login")
102102
.urlsConsent("http://localhost:" + springBootAppPort + "/consent")
103103
.urlsSelfIssuer(
104104
"http://localhost:" + springBootAppPort + "/integration-test-public-proxy")
105105
.build();
106-
dockerComposeEnvironment.start();
106+
oryHydraContainer.start();
107107

108108
// Late-bind the two Hydra endpoints now that the mapped ports exist (the circular
109109
// port dependency: the app and Hydra each need the other's randomized URI). Two consumers,
110110
// two different endpoints: the app's HydraAdminClient speaks the admin API, while the
111111
// test's public proxy forwards browsers to the public authorize endpoint.
112-
properties.setBasePath(dockerComposeEnvironment.adminBaseUriString());
113-
forwardingController.hydraPublicBaseUri = dockerComposeEnvironment.publicBaseUriString();
112+
properties.setBasePath(oryHydraContainer.adminBaseUriString());
113+
forwardingController.hydraPublicBaseUri = oryHydraContainer.publicBaseUriString();
114114
}
115115

116116
@AfterAll
117117
void stopTestEnvironment() {
118118
playwright.close();
119-
dockerComposeEnvironment.stop();
119+
oryHydraContainer.stop();
120120
}
121121

122122
@BeforeEach
@@ -127,7 +127,7 @@ public void registerTestClient() {
127127
clientId = "test-client-" + UUID.randomUUID();
128128
clientSecret = "client-secret";
129129
redirectUri = "http://localhost:" + springBootAppPort + CLIENT_CALL_BACK_PATH;
130-
dockerComposeEnvironment.createOrReplaceClient(
130+
oryHydraContainer.createOrReplaceClient(
131131
client ->
132132
client
133133
.clientId(clientId)
@@ -148,8 +148,7 @@ public void registerTestClient() {
148148
void requestToJwksUriReturns200() throws IOException, InterruptedException {
149149
val request =
150150
HttpRequest.newBuilder(
151-
URI.create(
152-
dockerComposeEnvironment.publicBaseUriString() + "/.well-known/jwks.json"))
151+
URI.create(oryHydraContainer.publicBaseUriString() + "/.well-known/jwks.json"))
153152
.build();
154153
val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
155154

@@ -180,7 +179,7 @@ public void loginInvalidCredentials() {
180179

181180
private URI getUriToInitiateFlow() {
182181
try {
183-
return new URIBuilder(dockerComposeEnvironment.publicBaseUriString() + "/oauth2/auth")
182+
return new URIBuilder(oryHydraContainer.publicBaseUriString() + "/oauth2/auth")
184183
.addParameter("response_type", "code")
185184
.addParameter("client_id", clientId)
186185
.addParameter("redirect_uri", redirectUri)
@@ -291,7 +290,7 @@ private CodeExchangeResponse exchangeCode(String code) {
291290

292291
val request =
293292
HttpRequest.newBuilder()
294-
.uri(URI.create(dockerComposeEnvironment.publicBaseUriString() + "/oauth2/token"))
293+
.uri(URI.create(oryHydraContainer.publicBaseUriString() + "/oauth2/token"))
295294
.header("Content-Type", "application/x-www-form-urlencoded")
296295
.header(
297296
"authorization",

0 commit comments

Comments
 (0)