Skip to content

Commit b2a6c95

Browse files
wassimoovinckr
authored andcommitted
feat: add Java integration examples and tests for kratos
1 parent 1159137 commit b2a6c95

22 files changed

Lines changed: 750 additions & 1 deletion

File tree

.github/workflows/integration-tests.yml

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: JavaScript Integration Tests
1+
name: Integration Tests
22

33
on:
44
workflow_dispatch:
@@ -31,3 +31,40 @@ jobs:
3131
ORY_SDK_URL: ${{ secrets.ORY_SDK_URL }}
3232
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
3333
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
34+
35+
test-java-integration:
36+
timeout-minutes: 10
37+
runs-on: ubuntu-latest
38+
steps:
39+
- uses: actions/checkout@v4
40+
- uses: actions/setup-java@v4
41+
with:
42+
java-version: "17"
43+
distribution: "temurin"
44+
cache: "maven"
45+
- name: Install test app dependencies
46+
run: |
47+
cd tests/jest/apps/identity-get-started-java
48+
mvn dependency:resolve
49+
- name: Start test server
50+
run: |
51+
cd tests/jest/apps/identity-get-started-java
52+
mvn spring-boot:run &
53+
env:
54+
ORY_SDK_URL: ${{ secrets.ORY_SDK_URL }}
55+
EXAMPLES_TEST_APP_PORT: "3000"
56+
- name: Wait for server to be ready
57+
run: |
58+
timeout 30 bash -c 'until curl -f http://127.0.0.1:3000/configure; do sleep 1; done'
59+
- name: Run Java integration tests
60+
run: |
61+
cd tests/jest/apps/identity-get-started-java
62+
mvn test
63+
env:
64+
ORY_SDK_URL: ${{ secrets.ORY_SDK_URL }}
65+
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
66+
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
67+
- name: Stop test server
68+
if: always()
69+
run: |
70+
pkill -f "spring-boot:run" || true
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import jakarta.servlet.http.HttpServletRequest;
2+
import jakarta.servlet.http.HttpServletResponse;
3+
import org.springframework.web.bind.annotation.GetMapping;
4+
import org.springframework.web.bind.annotation.RestController;
5+
import sh.ory.ApiException;
6+
import sh.ory.api.FrontendApi;
7+
import sh.ory.model.Session;
8+
9+
import java.io.IOException;
10+
11+
@RestController
12+
public class LoginHandler {
13+
private final FrontendApi ory;
14+
private final String baseUrl;
15+
16+
public LoginHandler(FrontendApi ory, String baseUrl) {
17+
this.ory = ory;
18+
this.baseUrl = baseUrl;
19+
}
20+
21+
@GetMapping("/login")
22+
public void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
23+
String cookieHeader = request.getHeader("Cookie");
24+
25+
try {
26+
Session session = ory.toSession(null, cookieHeader, null);
27+
if (session != null && session.getActive() != null && session.getActive()) {
28+
// Session is valid, return session data as JSON
29+
response.setContentType("application/json");
30+
response.setStatus(HttpServletResponse.SC_OK);
31+
response.getWriter().write(session.toString());
32+
return;
33+
}
34+
} catch (ApiException e) {
35+
// Session is invalid or doesn't exist
36+
}
37+
38+
// Redirect to login page
39+
response.sendRedirect(baseUrl + "/self-service/login/browser");
40+
}
41+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import jakarta.servlet.http.HttpServletRequest;
2+
import jakarta.servlet.http.HttpServletResponse;
3+
import org.springframework.web.bind.annotation.GetMapping;
4+
import org.springframework.web.bind.annotation.RestController;
5+
import sh.ory.ApiException;
6+
import sh.ory.api.FrontendApi;
7+
import sh.ory.model.LogoutFlow;
8+
9+
import java.io.IOException;
10+
11+
@RestController
12+
public class LogoutHandler {
13+
private final FrontendApi ory;
14+
15+
public LogoutHandler(FrontendApi ory) {
16+
this.ory = ory;
17+
}
18+
19+
@GetMapping("/logout")
20+
public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
21+
String cookieHeader = request.getHeader("Cookie");
22+
23+
try {
24+
LogoutFlow logoutFlow = ory.createBrowserLogoutFlow(cookieHeader);
25+
String logoutUrl = logoutFlow.getLogoutUrl();
26+
if (logoutUrl != null) {
27+
response.sendRedirect(logoutUrl);
28+
return;
29+
}
30+
} catch (ApiException e) {
31+
// Error creating logout flow
32+
}
33+
34+
// Redirect to home page if there's an error
35+
response.sendRedirect("/");
36+
}
37+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import sh.ory.ApiClient;
2+
import sh.ory.Configuration;
3+
import sh.ory.api.FrontendApi;
4+
5+
public class SetupDev {
6+
public static final String baseUrl = System.getenv("ORY_SDK_URL") != null
7+
? System.getenv("ORY_SDK_URL")
8+
: "http://localhost:4000";
9+
10+
public static FrontendApi createOryClient() {
11+
ApiClient apiClient = Configuration.getDefaultApiClient();
12+
apiClient.setBasePath(baseUrl);
13+
return new FrontendApi(apiClient);
14+
}
15+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import jakarta.servlet.http.HttpServletRequest;
2+
import jakarta.servlet.http.HttpServletResponse;
3+
import org.springframework.web.bind.annotation.GetMapping;
4+
import org.springframework.web.bind.annotation.RestController;
5+
import sh.ory.ApiException;
6+
import sh.ory.api.FrontendApi;
7+
import sh.ory.model.Session;
8+
9+
import java.io.IOException;
10+
11+
@RestController
12+
public class SignUpHandler {
13+
private final FrontendApi ory;
14+
private final String baseUrl;
15+
16+
public SignUpHandler(FrontendApi ory, String baseUrl) {
17+
this.ory = ory;
18+
this.baseUrl = baseUrl;
19+
}
20+
21+
@GetMapping("/signup")
22+
public void signUp(HttpServletRequest request, HttpServletResponse response) throws IOException {
23+
String cookieHeader = request.getHeader("Cookie");
24+
25+
try {
26+
Session session = ory.toSession(null, cookieHeader, null);
27+
if (session != null && session.getActive() != null && session.getActive()) {
28+
// Session is valid, return session data as JSON
29+
response.setContentType("application/json");
30+
response.setStatus(HttpServletResponse.SC_OK);
31+
response.getWriter().write(session.toString());
32+
return;
33+
}
34+
} catch (ApiException e) {
35+
// Session is invalid or doesn't exist
36+
}
37+
38+
// Redirect to registration page
39+
response.sendRedirect(baseUrl + "/self-service/registration/browser");
40+
}
41+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package session;
2+
3+
import jakarta.servlet.http.HttpServletResponse;
4+
import org.springframework.web.bind.annotation.GetMapping;
5+
import org.springframework.web.bind.annotation.RestController;
6+
7+
import java.io.IOException;
8+
9+
@RestController
10+
public class RefreshSessionHandler {
11+
private final String baseUrl;
12+
13+
public RefreshSessionHandler(String baseUrl) {
14+
this.baseUrl = baseUrl;
15+
}
16+
17+
@GetMapping("/refresh-session")
18+
public void refreshSession(HttpServletResponse response) throws IOException {
19+
// Redirect to login with refresh=true parameter
20+
response.sendRedirect(baseUrl + "/ui/login?refresh=true");
21+
}
22+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package session;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
import jakarta.servlet.http.HttpServletResponse;
5+
import org.springframework.web.servlet.HandlerInterceptor;
6+
import sh.ory.ApiException;
7+
import sh.ory.api.FrontendApi;
8+
import sh.ory.model.Session;
9+
10+
import java.io.IOException;
11+
12+
public class RequireAuth implements HandlerInterceptor {
13+
private final FrontendApi ory;
14+
private final String baseUrl;
15+
16+
public RequireAuth(FrontendApi ory, String baseUrl) {
17+
this.ory = ory;
18+
this.baseUrl = baseUrl;
19+
}
20+
21+
@Override
22+
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
23+
String cookieHeader = request.getHeader("Cookie");
24+
25+
try {
26+
Session session = ory.toSession(null, cookieHeader, null);
27+
if (session != null && session.getActive() != null && session.getActive()) {
28+
// Store session in request attribute
29+
request.setAttribute("session", session);
30+
return true;
31+
}
32+
} catch (ApiException e) {
33+
// Session is invalid or doesn't exist
34+
}
35+
36+
// Redirect to login page
37+
response.sendRedirect(baseUrl + "/self-service/login/browser");
38+
return false;
39+
}
40+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package session;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
import org.springframework.http.ResponseEntity;
5+
import org.springframework.web.bind.annotation.GetMapping;
6+
import org.springframework.web.bind.annotation.RestController;
7+
import sh.ory.model.Session;
8+
9+
@RestController
10+
public class SessionHandler {
11+
@GetMapping("/session")
12+
public ResponseEntity<Object> getSession(HttpServletRequest request) {
13+
Session session = (Session) request.getAttribute("session");
14+
if (session != null && session.getIdentity() != null && session.getIdentity().getTraits() != null) {
15+
return ResponseEntity.ok(session.getIdentity().getTraits());
16+
}
17+
return ResponseEntity.notFound().build();
18+
}
19+
}

docs/identities/get-started/session-management.mdx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import nextRefreshSession from '!!raw-loader!./_common/code-examples/nextjs/sess
1515
import nextCheckSession from '!!raw-loader!./_common/code-examples/nextjs/session/middleware.ts'
1616
import goCheckSession from '!!raw-loader!./_common/code-examples/go/middleware.go'
1717
import goRefreshHandler from '!!raw-loader!./_common/code-examples/go/refresh_handler.go'
18+
import javaRequireAuth from '!!raw-loader!./_common/code-examples/java/session/RequireAuth.java'
19+
import javaSessionHandler from '!!raw-loader!./_common/code-examples/java/session/SessionHandler.java'
20+
import javaRefreshSession from '!!raw-loader!./_common/code-examples/java/session/RefreshSessionHandler.java'
1821
```
1922

2023
After a user has logged in, Ory creates a session cookie that your application can use to verify the user's authentication status.
@@ -51,6 +54,19 @@ You can protect routes by checking for a session cookie.
5154
<CodeBlock language="go" title="middleware.go">{goCheckSession}</CodeBlock>
5255
```
5356

57+
```mdx-code-block
58+
</TabItem>
59+
<TabItem value="java">
60+
```
61+
62+
```mdx-code-block
63+
<CodeBlock language="java" title="RequireAuth.java">{javaRequireAuth}</CodeBlock>
64+
```
65+
66+
```mdx-code-block
67+
<CodeBlock language="java" title="SessionHandler.java">{javaSessionHandler}</CodeBlock>
68+
```
69+
5470
```mdx-code-block
5571
</TabItem>
5672
</FrameworkCodeTabs>
@@ -87,6 +103,15 @@ You can refresh user sessions to extend their expiration time:
87103
<CodeBlock className="language-go" title="refresh_handler.go">{goRefreshHandler}</CodeBlock>
88104
```
89105

106+
```mdx-code-block
107+
</TabItem>
108+
<TabItem value="java">
109+
```
110+
111+
```mdx-code-block
112+
<CodeBlock className="language-java" title="RefreshSessionHandler.java">{javaRefreshSession}</CodeBlock>
113+
```
114+
90115
```mdx-code-block
91116
</TabItem>
92117
</FrameworkCodeTabs>

docs/identities/get-started/sign-in.mdx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { FrameworkCodeTabs } from '@site/src/components/GuidesComponents'
1515
import jsLogin from '!!raw-loader!./_common/code-examples/js/login.js'
1616
import goLogin from '!!raw-loader!./_common/code-examples/go/login_handler.go'
1717
import nextjsLogin from '!!raw-loader!./_common/code-examples/nextjs/login.tsx'
18+
import javaLogin from '!!raw-loader!./_common/code-examples/java/LoginHandler.java'
1819
```
1920

2021
The sign in flow follows the same pattern as the [sign up flow](/docs/identities/get-started/sign-up) but instead of redirecting
@@ -48,6 +49,15 @@ to the registration page, it redirects to the login page.
4849
4950
```
5051

52+
```mdx-code-block
53+
</TabItem>
54+
<TabItem value="java">
55+
```
56+
57+
```mdx-code-block
58+
<CodeBlock className="language-java" title={"LoginHandler.java"}>{javaLogin}</CodeBlock>
59+
```
60+
5161
```mdx-code-block
5262
</TabItem>
5363
</FrameworkCodeTabs>

0 commit comments

Comments
 (0)