Skip to content

Commit 15d596a

Browse files
author
muha
committed
spring boot 3.4
1 parent 2941ad1 commit 15d596a

File tree

11 files changed

+126
-178
lines changed

11 files changed

+126
-178
lines changed

README.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
# HelseID Java client with Spring Security
22
#### PKCE [RFC 7636] (Proof Key for Code Exchange) , PAR [RFC 9126] (Pushed Authorization Requests), and DPoP [RFC 9449]
33

4-
## ID Token
5-
[http://localhost:8089/api/token-info](http://localhost:8089/api/token-info)
4+
HelseId OAuth2 flows (Authorization Code and Client Credentials) using the spring boot. It includes examples of securing API calls with oAuth2 and DPoP.
5+
6+
### 1. Authorization Code Flow
7+
1. Navigate to the `authorization-code` project and start the application:
8+
```bash
9+
cd authorization-code
10+
mvn spring-boot:run
11+
```
12+
2. Test the Authorization Code Flow:
13+
14+
Access the application at http://localhost:8089.
15+
16+
View the ID Token details at http://localhost:8089/api/token-info.
17+
18+
19+
### 2. Client Credentials with API Security Validation
20+
1. Navigate to the `authorization-code` project and start the application
21+
```bash
22+
cd demo-api
23+
mvn spring-boot:run
24+
```
25+
26+
2. Navigate to the `client-credentials` project and start the **client-credentials** application:
27+
```bash
28+
cd client-credentials
29+
mvn spring-boot:run
30+
```
31+
3. The `ClientCredentialsExample` class in `client-credentials` will call demo-api with OAuth tokens and DPoP tokens.

authorization-code/pom.xml

Lines changed: 62 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,77 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5-
<modelVersion>4.0.0</modelVersion>
6-
<parent>
7-
<groupId>com.example</groupId>
8-
<artifactId>client-parent</artifactId>
9-
<version>1.0-SNAPSHOT</version>
10-
<relativePath>../pom.xml</relativePath>
11-
</parent>
12-
<artifactId>authorization-code</artifactId>
13-
<name>HelseID authorization code</name>
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>com.example</groupId>
8+
<artifactId>helseid-client-parent</artifactId>
9+
<version>${revision}</version>
10+
<relativePath>../pom.xml</relativePath>
11+
</parent>
12+
<artifactId>authorization-code</artifactId>
13+
<name>HelseID authorization code</name>
1414

15-
<dependencies>
16-
<dependency>
17-
<groupId>com.example</groupId>
18-
<artifactId>common</artifactId>
19-
</dependency>
15+
<dependencies>
16+
<dependency>
17+
<groupId>com.example</groupId>
18+
<artifactId>common</artifactId>
19+
</dependency>
2020

21-
<dependency>
22-
<groupId>org.springframework.boot</groupId>
23-
<artifactId>spring-boot-starter-web</artifactId>
24-
</dependency>
21+
<dependency>
22+
<groupId>org.springframework.boot</groupId>
23+
<artifactId>spring-boot-starter-web</artifactId>
24+
</dependency>
2525

26-
<dependency>
27-
<groupId>org.springframework.boot</groupId>
28-
<artifactId>spring-boot-starter-thymeleaf</artifactId>
29-
</dependency>
26+
<dependency>
27+
<groupId>org.springframework.boot</groupId>
28+
<artifactId>spring-boot-starter-thymeleaf</artifactId>
29+
</dependency>
3030

31-
<dependency>
32-
<groupId>org.springframework.boot</groupId>
33-
<artifactId>spring-boot-starter-security</artifactId>
34-
</dependency>
31+
<dependency>
32+
<groupId>org.springframework.boot</groupId>
33+
<artifactId>spring-boot-starter-security</artifactId>
34+
</dependency>
3535

36-
<dependency>
37-
<groupId>org.springframework.boot</groupId>
38-
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
39-
</dependency>
36+
<dependency>
37+
<groupId>org.springframework.boot</groupId>
38+
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
39+
</dependency>
4040

41-
<dependency>
42-
<groupId>org.springframework.security</groupId>
43-
<artifactId>spring-security-oauth2-client</artifactId>
44-
</dependency>
41+
<dependency>
42+
<groupId>org.springframework.security</groupId>
43+
<artifactId>spring-security-oauth2-client</artifactId>
44+
</dependency>
4545

46-
<dependency>
47-
<groupId>org.springframework.security</groupId>
48-
<artifactId>spring-security-oauth2-jose</artifactId>
49-
</dependency>
46+
<dependency>
47+
<groupId>org.springframework.security</groupId>
48+
<artifactId>spring-security-oauth2-jose</artifactId>
49+
</dependency>
5050

51-
<dependency>
52-
<groupId>org.json</groupId>
53-
<artifactId>json</artifactId>
54-
<version>20211205</version>
55-
</dependency>
51+
<dependency>
52+
<groupId>org.json</groupId>
53+
<artifactId>json</artifactId>
54+
</dependency>
5655

57-
<dependency>
58-
<groupId>org.springframework.boot</groupId>
59-
<artifactId>spring-boot-configuration-processor</artifactId>
60-
<optional>true</optional>
61-
</dependency>
56+
<dependency>
57+
<groupId>org.springframework.boot</groupId>
58+
<artifactId>spring-boot-configuration-processor</artifactId>
59+
<optional>true</optional>
60+
</dependency>
6261

63-
<dependency>
64-
<groupId>com.sun.activation</groupId>
65-
<artifactId>jakarta.activation</artifactId>
66-
</dependency>
62+
<dependency>
63+
<groupId>org.bouncycastle</groupId>
64+
<artifactId>bcpkix-jdk18on</artifactId>
65+
</dependency>
6766

68-
<dependency>
69-
<groupId>com.sun.xml.bind</groupId>
70-
<artifactId>jaxb-impl</artifactId>
71-
</dependency>
67+
<dependency>
68+
<groupId>org.apache.httpcomponents.client5</groupId>
69+
<artifactId>httpclient5</artifactId>
70+
</dependency>
7271

73-
<dependency>
74-
<groupId>com.sun.xml.bind</groupId>
75-
<artifactId>jaxb-core</artifactId>
76-
</dependency>
77-
78-
<dependency>
79-
<groupId>org.bouncycastle</groupId>
80-
<artifactId>bcpkix-jdk18on</artifactId>
81-
</dependency>
82-
83-
<dependency>
84-
<groupId>org.apache.httpcomponents.client5</groupId>
85-
<artifactId>httpclient5</artifactId>
86-
</dependency>
87-
88-
<dependency>
89-
<groupId>org.projectlombok</groupId>
90-
<artifactId>lombok</artifactId>
91-
</dependency>
92-
</dependencies>
72+
<dependency>
73+
<groupId>org.projectlombok</groupId>
74+
<artifactId>lombok</artifactId>
75+
</dependency>
76+
</dependencies>
9377
</project>

client-credentials/pom.xml

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<modelVersion>4.0.0</modelVersion>
66
<parent>
77
<groupId>com.example</groupId>
8-
<artifactId>client-parent</artifactId>
9-
<version>1.0-SNAPSHOT</version>
8+
<artifactId>helseid-client-parent</artifactId>
9+
<version>${revision}</version>
1010
<relativePath>../pom.xml</relativePath>
1111
</parent>
1212
<artifactId>client-credentials</artifactId>
@@ -46,7 +46,6 @@
4646
<dependency>
4747
<groupId>org.json</groupId>
4848
<artifactId>json</artifactId>
49-
<version>20211205</version>
5049
</dependency>
5150

5251
<dependency>
@@ -55,21 +54,6 @@
5554
<optional>true</optional>
5655
</dependency>
5756

58-
<dependency>
59-
<groupId>com.sun.activation</groupId>
60-
<artifactId>jakarta.activation</artifactId>
61-
</dependency>
62-
63-
<dependency>
64-
<groupId>com.sun.xml.bind</groupId>
65-
<artifactId>jaxb-impl</artifactId>
66-
</dependency>
67-
68-
<dependency>
69-
<groupId>com.sun.xml.bind</groupId>
70-
<artifactId>jaxb-core</artifactId>
71-
</dependency>
72-
7357
<dependency>
7458
<groupId>org.bouncycastle</groupId>
7559
<artifactId>bcpkix-jdk18on</artifactId>

client-credentials/src/main/java/com/example/ClientCredentialsExample.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,35 +32,38 @@ public void run(ApplicationArguments args) {
3232
OAuth2AccessToken accessToken = helseIDClientCredentialTokenService.getAccessToken();
3333
request(accessToken, requestUrl);
3434

35-
DPoPToken dPoPToken = helseIDDPoPClientCredentialTokenService.getAccessToken(
36-
requestUrl,
37-
HttpMethod.GET.name());
35+
DPoPToken dPoPToken =
36+
helseIDDPoPClientCredentialTokenService.getAccessToken(requestUrl, HttpMethod.GET.name());
3837
request(dPoPToken, requestUrl);
3938
}
4039

4140
private void request(OAuth2AccessToken accessToken, String requestUrl) {
42-
log.warn(accessToken.getTokenValue());
41+
log.warn("OAuth2 Token: " + accessToken.getTokenValue());
42+
log.warn("Scopes: " + String.join(", ", accessToken.getScopes()));
4343
RestTemplate restTemplate = restTemplateBuilder.build();
4444
HttpHeaders httpHeaders = new HttpHeaders();
4545
httpHeaders.setBearerAuth(accessToken.getTokenValue());
46-
ResponseEntity<String> responseEntity = restTemplate.exchange(
47-
requestUrl, HttpMethod.GET,
48-
new HttpEntity<String>(httpHeaders), String.class);
46+
ResponseEntity<String> responseEntity =
47+
restTemplate.exchange(
48+
requestUrl, HttpMethod.GET, new HttpEntity<String>(httpHeaders), String.class);
4949
if (responseEntity.hasBody()) {
50-
log.error("Response from API: " + responseEntity.getBody());
50+
log.info("Response from API: " + responseEntity.getBody());
5151
}
5252
}
5353

5454
private void request(DPoPToken dPoPToken, String requestUrl) {
55+
log.warn("DPoP Token: " + dPoPToken.getTokenValue());
56+
log.warn("DPoP Header: " + dPoPToken.getDPoPHeader());
57+
log.warn("Scopes: " + String.join(", ", dPoPToken.getScopes()));
5558
RestTemplate restTemplate = restTemplateBuilder.build();
5659
HttpHeaders httpHeaders = new HttpHeaders();
5760
httpHeaders.set("Authorization", "DPoP " + dPoPToken.getTokenValue());
5861
httpHeaders.set("DPoP", dPoPToken.getDPoPHeader());
59-
ResponseEntity<String> responseEntity = restTemplate.exchange(
60-
requestUrl, HttpMethod.GET,
61-
new HttpEntity<String>(httpHeaders), String.class);
62+
ResponseEntity<String> responseEntity =
63+
restTemplate.exchange(
64+
requestUrl, HttpMethod.GET, new HttpEntity<String>(httpHeaders), String.class);
6265
if (responseEntity.hasBody()) {
63-
log.error("Response from API using DPoP: " + responseEntity.getBody());
66+
log.info("Response from API using DPoP: " + responseEntity.getBody());
6467
}
6568
}
6669
}

common/pom.xml

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
<parent>
88
<groupId>com.example</groupId>
9-
<artifactId>client-parent</artifactId>
10-
<version>1.0-SNAPSHOT</version>
9+
<artifactId>helseid-client-parent</artifactId>
10+
<version>${revision}</version>
1111
<relativePath>../pom.xml</relativePath>
1212
</parent>
1313

@@ -43,21 +43,6 @@
4343
<optional>true</optional>
4444
</dependency>
4545

46-
<dependency>
47-
<groupId>com.sun.activation</groupId>
48-
<artifactId>jakarta.activation</artifactId>
49-
</dependency>
50-
51-
<dependency>
52-
<groupId>com.sun.xml.bind</groupId>
53-
<artifactId>jaxb-impl</artifactId>
54-
</dependency>
55-
56-
<dependency>
57-
<groupId>com.sun.xml.bind</groupId>
58-
<artifactId>jaxb-core</artifactId>
59-
</dependency>
60-
6146
<dependency>
6247
<groupId>org.bouncycastle</groupId>
6348
<artifactId>bcpkix-jdk18on</artifactId>

common/src/main/java/com/example/service/JwtClientAssertionParametersService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public class JwtClientAssertionParametersService {
5959
{
6060
"system":"urn:oid:2.16.578.1.12.4.1.2.101",
6161
"type":"ENH",
62-
"value":"%s",
62+
"value":"%s"
6363
}
6464
}
6565
}

common/src/main/java/com/example/utils/JWK2PEM.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public static String getPem(InputStream inputStream) {
4141
for (int length; (length = inputStream.read(buffer)) != -1; ) {
4242
result.write(buffer, 0, length);
4343
}
44-
JSONObject jsonObject = new JSONObject(result.toString(StandardCharsets.UTF_8.name()));
44+
JSONObject jsonObject = new JSONObject(result.toString(StandardCharsets.UTF_8));
4545
return getPem(jsonObject);
4646
} catch (Exception e) {
4747
log.error(e.getMessage(), e);

demo-api/pom.xml

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
<modelVersion>4.0.0</modelVersion>
66
<parent>
77
<groupId>com.example</groupId>
8-
<artifactId>client-parent</artifactId>
9-
<version>1.0-SNAPSHOT</version>
8+
<artifactId>helseid-client-parent</artifactId>
9+
<version>${revision}</version>
1010
<relativePath>../pom.xml</relativePath>
1111
</parent>
12+
1213
<artifactId>demo-api</artifactId>
1314
<name>HelseID demo api</name>
1415

@@ -43,11 +44,9 @@
4344
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
4445
</dependency>
4546

46-
4747
<dependency>
4848
<groupId>org.json</groupId>
4949
<artifactId>json</artifactId>
50-
<version>20211205</version>
5150
</dependency>
5251

5352
<dependency>
@@ -56,21 +55,6 @@
5655
<optional>true</optional>
5756
</dependency>
5857

59-
<dependency>
60-
<groupId>com.sun.activation</groupId>
61-
<artifactId>jakarta.activation</artifactId>
62-
</dependency>
63-
64-
<dependency>
65-
<groupId>com.sun.xml.bind</groupId>
66-
<artifactId>jaxb-impl</artifactId>
67-
</dependency>
68-
69-
<dependency>
70-
<groupId>com.sun.xml.bind</groupId>
71-
<artifactId>jaxb-core</artifactId>
72-
</dependency>
73-
7458
<dependency>
7559
<groupId>org.bouncycastle</groupId>
7660
<artifactId>bcpkix-jdk18on</artifactId>

demo-api/src/main/java/com/example/controller/SecureResource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ public ResponseEntity<?> secured() {
1818
@RequestMapping("/api/client-name")
1919
public ResponseEntity<?> secureEndpoint(@AuthenticationPrincipal Jwt user) {
2020
String clinetName = (String) user.getClaims().get("helseid://claims/client/client_name");
21-
return new ResponseEntity<>(clinetName, HttpStatus.OK);
21+
String clinetOrgnr = (String) user.getClaims().get("helseid://claims/client/claims/orgnr_parent");
22+
return new ResponseEntity<>(clinetName + "[" + clinetOrgnr + "]", HttpStatus.OK);
2223
}
2324

2425
@RequestMapping("/api/token-info")

0 commit comments

Comments
 (0)