Skip to content

Commit 477acfd

Browse files
committed
changed configuration from a single user to multiple users
1 parent ad5b3e3 commit 477acfd

File tree

5 files changed

+72
-63
lines changed

5 files changed

+72
-63
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
(c) 2020 Martin Kuba, CESNET
44

55
This application implements an OpenID Connect (OIDC) Authorization Server (AS) that
6-
provides just one user. Its purpose is to provide a temporary OIDC AS that can be
6+
provides a constant set of users. Its original purpose was to provide a temporary OIDC AS that can be
77
used after deployment of an OIDC client and an OIDC resource server to set them up before
8-
a real OIDC server is deployed.
8+
a real OIDC server is deployed. But it can be used for other purposes like testing.
99

1010
This fake server has the following features:
1111
* it is implemented in Java as Spring Boot application
12+
* is deployed as JAR file executable on Linux
1213
* implements the following grant types:
1314
* **Implicit Grant flow** (for JavaScript clients - deprecated)
1415
* **Authorization Code flow with Proof Key for Code Exchange** (for JavaScript clients - recommended)

pom.xml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55
<parent>
66
<groupId>org.springframework.boot</groupId>
77
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>2.4.5</version>
8+
<version>2.6.3</version>
99
</parent>
1010
<groupId>cz.metacentrum</groupId>
1111
<artifactId>fake_oidc</artifactId>
12-
<version>1.2.0</version>
12+
<version>1.3.0</version>
1313
<name>fake_oidc</name>
1414
<description>Fake OpenId Connect Authorization Server</description>
1515

1616
<properties>
17-
<java.version>11</java.version>
17+
<java.version>17</java.version>
1818
</properties>
1919

2020
<dependencies>
@@ -44,7 +44,7 @@
4444
<dependency>
4545
<groupId>com.nimbusds</groupId>
4646
<artifactId>nimbus-jose-jwt</artifactId>
47-
<version>8.19</version>
47+
<version>9.16.1</version>
4848
</dependency>
4949
</dependencies>
5050

@@ -54,15 +54,12 @@
5454
<plugin>
5555
<groupId>org.springframework.boot</groupId>
5656
<artifactId>spring-boot-maven-plugin</artifactId>
57+
<configuration>
58+
<!-- https://docs.spring.io/spring-boot/docs/current/reference/html/deployment.html#deployment.installing -->
59+
<executable>true</executable>
60+
</configuration>
5761
</plugin>
5862
</plugins>
5963
</build>
60-
<distributionManagement>
61-
<repository>
62-
<id>github</id>
63-
<name>GitHub Packages</name>
64-
<url>https://maven.pkg.github.com/CESNET/fake-oidc-server</url>
65-
</repository>
66-
</distributionManagement>
6764

6865
</project>

src/main/java/cz/metacentrum/fake_oidc/FakeOidcServerProperties.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@
33
import org.springframework.boot.context.properties.ConfigurationProperties;
44
import org.springframework.stereotype.Component;
55

6+
import java.util.List;
7+
68
@Component
79
@ConfigurationProperties(prefix="oidc")
810
public class FakeOidcServerProperties {
911

10-
private User user;
12+
private List<User> users;
1113
private long tokenExpirationSeconds;
1214

13-
public User getUser() {
14-
return user;
15+
public List<User> getUsers() {
16+
return users;
1517
}
1618

17-
public void setUser(User user) {
18-
this.user = user;
19+
public void setUsers(List<User> users) {
20+
this.users = users;
1921
}
2022

2123
public long getTokenExpirationSeconds() {
@@ -29,7 +31,7 @@ public void setTokenExpirationSeconds(long tokenExpirationSeconds) {
2931
@Override
3032
public String toString() {
3133
return "FakeOidcServerProperties{" +
32-
"user=" + user +
34+
"users=" + users +
3335
", tokenExpirationSeconds=" + tokenExpirationSeconds +
3436
'}';
3537
}

src/main/java/cz/metacentrum/fake_oidc/OidcController.java

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import org.springframework.http.HttpStatus;
1919
import org.springframework.http.MediaType;
2020
import org.springframework.http.ResponseEntity;
21-
import org.springframework.util.Base64Utils;
2221
import org.springframework.web.bind.annotation.CrossOrigin;
2322
import org.springframework.web.bind.annotation.RequestHeader;
2423
import org.springframework.web.bind.annotation.RequestMapping;
@@ -43,6 +42,7 @@
4342
import java.util.HashMap;
4443
import java.util.HashSet;
4544
import java.util.LinkedHashMap;
45+
import java.util.List;
4646
import java.util.Map;
4747
import java.util.Set;
4848
import java.util.UUID;
@@ -136,7 +136,7 @@ public ResponseEntity<?> userinfo(@RequestHeader("Authorization") String auth,
136136
HttpServletRequest req) {
137137
log.info("called " + USERINFO_ENDPOINT + " from {}", req.getRemoteHost());
138138
if (!auth.startsWith("Bearer ")) {
139-
if(access_token == null) {
139+
if (access_token == null) {
140140
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("No token");
141141
}
142142
auth = access_token;
@@ -217,7 +217,7 @@ public ResponseEntity<?> token(@RequestParam String grant_type,
217217
}
218218
if (codeInfo.codeChallenge != null) {
219219
// check PKCE
220-
if(code_verifier == null) {
220+
if (code_verifier == null) {
221221
return jsonError("invalid_request", "code_verifier missing");
222222
}
223223
if ("S256".equals(codeInfo.codeChallengeMethod)) {
@@ -274,39 +274,40 @@ public ResponseEntity<?> authorize(@RequestParam String client_id,
274274
String[] creds = new String(Base64.getDecoder().decode(auth.split(" ")[1])).split(":", 2);
275275
String login = creds[0];
276276
String password = creds[1];
277-
User user = serverProperties.getUser();
278-
if (user.getLogname().equals(login) && user.getPassword().equals(password)) {
279-
log.info("password for user {} is correct", login);
280-
Set<String> responseType = setFromSpaceSeparatedString(response_type);
281-
String iss = uriBuilder.replacePath("/").build().encode().toUriString();
282-
if (responseType.contains("token")) {
283-
// implicit flow
284-
log.info("using implicit flow");
285-
String access_token = createAccessToken(iss, user, client_id, scope);
286-
String id_token = createIdToken(iss, user, client_id, nonce, access_token);
287-
String url = redirect_uri + "#" +
288-
"access_token=" + urlencode(access_token) +
289-
"&token_type=Bearer" +
290-
"&state=" + urlencode(state) +
291-
"&expires_in=" + serverProperties.getTokenExpirationSeconds() +
292-
"&id_token=" + urlencode(id_token);
293-
return ResponseEntity.status(HttpStatus.FOUND).header("Location", url).build();
294-
} else if (responseType.contains("code")) {
295-
// authorization code flow
296-
log.info("using authorization code flow {}", code_challenge!=null ? "with PKCE" : "");
297-
String code = createAuthorizationCode(code_challenge, code_challenge_method, client_id, redirect_uri, user, iss, scope, nonce);
298-
String url = redirect_uri + "?" +
299-
"code=" + code +
300-
"&state=" + urlencode(state);
301-
return ResponseEntity.status(HttpStatus.FOUND).header("Location", url).build();
302-
} else {
303-
String url = redirect_uri + "#" + "error=unsupported_response_type";
304-
return ResponseEntity.status(HttpStatus.FOUND).header("Location", url).build();
277+
List<User> users = serverProperties.getUsers();
278+
for (User user : users) {
279+
if (user.getLogname().equals(login) && user.getPassword().equals(password)) {
280+
log.info("password for user {} is correct", login);
281+
Set<String> responseType = setFromSpaceSeparatedString(response_type);
282+
String iss = uriBuilder.replacePath("/").build().encode().toUriString();
283+
if (responseType.contains("token")) {
284+
// implicit flow
285+
log.info("using implicit flow");
286+
String access_token = createAccessToken(iss, user, client_id, scope);
287+
String id_token = createIdToken(iss, user, client_id, nonce, access_token);
288+
String url = redirect_uri + "#" +
289+
"access_token=" + urlencode(access_token) +
290+
"&token_type=Bearer" +
291+
"&state=" + urlencode(state) +
292+
"&expires_in=" + serverProperties.getTokenExpirationSeconds() +
293+
"&id_token=" + urlencode(id_token);
294+
return ResponseEntity.status(HttpStatus.FOUND).header("Location", url).build();
295+
} else if (responseType.contains("code")) {
296+
// authorization code flow
297+
log.info("using authorization code flow {}", code_challenge != null ? "with PKCE" : "");
298+
String code = createAuthorizationCode(code_challenge, code_challenge_method, client_id, redirect_uri, user, iss, scope, nonce);
299+
String url = redirect_uri + "?" +
300+
"code=" + code +
301+
"&state=" + urlencode(state);
302+
return ResponseEntity.status(HttpStatus.FOUND).header("Location", url).build();
303+
} else {
304+
String url = redirect_uri + "#" + "error=unsupported_response_type";
305+
return ResponseEntity.status(HttpStatus.FOUND).header("Location", url).build();
306+
}
305307
}
306-
} else {
307-
log.info("wrong user and password combination");
308-
return response401();
309308
}
309+
log.info("wrong user and password combination");
310+
return response401();
310311
}
311312
}
312313

src/main/resources/application.yml

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# every value can be changed from command line by preceding the option with --
22
# see https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-command-line-args
33
# example:
4-
# java -jar fake_oidc.jar --server.port=8100 -server.ssl.key-store=mykeystore.p12 --oidc.user.password=bflmpsvz
4+
# target/fake_oidc_server.jar --server.port=8100 -server.ssl.key-store=mykeystore.p12 --oidc.user.password=bflmpsvz
55

66
server:
77
port: 8090
@@ -13,12 +13,20 @@ server:
1313
key-store-password: password
1414
oidc:
1515
tokenExpirationSeconds: 36000
16-
user:
17-
logname: "perun"
18-
password: "test"
19-
sub: "perun1"
20-
name: "Master Perun"
21-
given_name: "Master"
22-
family_name: "Perun"
23-
preferred_username: "perun"
24-
email: "perun@cesnet.cz"
16+
users:
17+
- logname: "perun"
18+
password: "test"
19+
sub: "perun1"
20+
name: "Master Perun"
21+
given_name: "Master"
22+
family_name: "Perun"
23+
preferred_username: "perun"
24+
email: "perun@cesnet.cz"
25+
- logname: "makub"
26+
password: "test"
27+
sub: "makub1"
28+
name: "Martin Kuba"
29+
given_name: "Kuba"
30+
family_name: "Martin"
31+
preferred_username: "makub"
32+
email: "makub@ics.muni.cz"

0 commit comments

Comments
 (0)