Skip to content

Commit 980ccf3

Browse files
committed
implemented introspecion
1 parent 1a028ee commit 980ccf3

File tree

5 files changed

+41
-18
lines changed

5 files changed

+41
-18
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ mvn package
2323

2424
java -jar target/fake_oidc.jar
2525
```
26+
or build and run from maven:
27+
```bash
28+
mvn spring-boot:run
29+
```
2630

2731
By default the application runs at TCP port 8090, uses a self-signed certificate for localhost, and the only
2832
user has username "perun" and password "test". This can be changed by using command line options:

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
<parent>
66
<groupId>org.springframework.boot</groupId>
77
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>2.3.2.RELEASE</version>
8+
<version>2.3.3.RELEASE</version>
99
<relativePath/> <!-- lookup parent from repository -->
1010
</parent>
1111
<groupId>cz.metacentrum</groupId>
1212
<artifactId>fake_oidc</artifactId>
13-
<version>0.0.1-SNAPSHOT</version>
13+
<version>0.0.2-SNAPSHOT</version>
1414
<name>fake_oidc</name>
1515
<description>Fake OpenId Connect Authorization Server</description>
1616

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
public class FakeOidcProperties {
99

1010
private User user;
11+
private long tokenExpirationSeconds;
1112

1213
public User getUser() {
1314
return user;
@@ -17,10 +18,19 @@ public void setUser(User user) {
1718
this.user = user;
1819
}
1920

21+
public long getTokenExpirationSeconds() {
22+
return tokenExpirationSeconds;
23+
}
24+
25+
public void setTokenExpirationSeconds(long tokenExpirationSeconds) {
26+
this.tokenExpirationSeconds = tokenExpirationSeconds;
27+
}
28+
2029
@Override
2130
public String toString() {
2231
return "FakeOidcProperties{" +
2332
"user=" + user +
33+
", tokenExpirationSeconds=" + tokenExpirationSeconds +
2434
'}';
2535
}
2636
}

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

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
/**
4848
* Run with "mvn spring-boot:run".
4949
* <p>
50-
* Provides OIDC metadata. Seet the spec at https://openid.net/specs/openid-connect-discovery-1_0.html
50+
* Provides OIDC metadata. See the spec at https://openid.net/specs/openid-connect-discovery-1_0.html
5151
*/
5252
@RestController
5353
public class OidcController {
@@ -59,7 +59,7 @@ public class OidcController {
5959
public static final String TOKEN_ENDPOINT = "/token";
6060
public static final String USERINFO_ENDPOINT = "/userinfo";
6161
public static final String JWKS_ENDPOINT = "/jwks";
62-
public static final String INTROSPECTION_ENDPOINT = "/introspection";
62+
public static final String INTROSPECTION_ENDPOINT = "/introspect";
6363

6464
private JWSSigner signer;
6565
private JWKSet publicJWKSet;
@@ -84,7 +84,7 @@ public void init() throws IOException, ParseException, JOSEException {
8484
@RequestMapping(value = METADATA_ENDPOINT, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
8585
@CrossOrigin
8686
public ResponseEntity<?> metadata(UriComponentsBuilder uriBuilder, HttpServletRequest req) {
87-
log.info(METADATA_ENDPOINT + " from {}", req.getRemoteHost());
87+
log.info("called " + METADATA_ENDPOINT + " from {}", req.getRemoteHost());
8888
String urlPrefix = uriBuilder.replacePath(null).build().encode().toUriString();
8989
Map<String, Object> m = new LinkedHashMap<>();
9090
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
@@ -104,15 +104,15 @@ public ResponseEntity<?> metadata(UriComponentsBuilder uriBuilder, HttpServletRe
104104

105105
@RequestMapping(value = JWKS_ENDPOINT, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
106106
@CrossOrigin
107-
public ResponseEntity<String> jwks() {
108-
log.info("/jwks");
107+
public ResponseEntity<String> jwks(HttpServletRequest req) {
108+
log.info("called " + JWKS_ENDPOINT + " from {}", req.getRemoteHost());
109109
return ResponseEntity.ok().body(publicJWKSet.toString());
110110
}
111111

112112
@RequestMapping(value = USERINFO_ENDPOINT, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
113113
@CrossOrigin(allowedHeaders = {"Authorization", "Content-Type"})
114-
public ResponseEntity<?> userinfo(@RequestHeader("Authorization") String auth) {
115-
log.info("/userinfo");
114+
public ResponseEntity<?> userinfo(@RequestHeader("Authorization") String auth, HttpServletRequest req) {
115+
log.info("called " + USERINFO_ENDPOINT + " from {}", req.getRemoteHost());
116116
if (!auth.startsWith("Bearer ")) {
117117
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("No token");
118118
}
@@ -134,17 +134,24 @@ public ResponseEntity<?> userinfo(@RequestHeader("Authorization") String auth) {
134134

135135
@RequestMapping(value = INTROSPECTION_ENDPOINT, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
136136
public ResponseEntity<?> introspection(@RequestParam String token,
137-
@RequestHeader("Authorization") String auth) {
138-
log.info("/introspection auth = {} token= {}", auth, token);
137+
@RequestHeader("Authorization") String auth,
138+
UriComponentsBuilder uriBuilder,
139+
HttpServletRequest req) {
140+
log.info("called " + INTROSPECTION_ENDPOINT + " from {}", req.getRemoteHost());
139141
Map<String, Object> m = new LinkedHashMap<>();
140142
AccessTokenInfo accessTokenInfo = accessTokens.get(token);
141143
if( accessTokenInfo == null) {
144+
log.error("token not found in memory: {}", token);
142145
m.put("active", false);
143146
} else {
147+
String scopes = String.join(" ", accessTokenInfo.scopes);
148+
log.info("token found, releasing scopes: {}", scopes);
149+
m.put("iss", uriBuilder.replacePath(null).build().encode().toUriString() + "/");
144150
m.put("active", true);
145-
m.put("scope", String.join(" ", accessTokenInfo.scopes));
151+
m.put("scope", scopes);
146152
m.put("username", accessTokenInfo.user.getSub());
147153
m.put("sub", accessTokenInfo.user.getSub());
154+
m.put("exp", accessTokenInfo.expiration.toInstant().toEpochMilli());
148155
}
149156
return ResponseEntity.ok().body(m);
150157
}
@@ -157,8 +164,10 @@ public ResponseEntity<?> authorize(@RequestParam String client_id,
157164
@RequestParam String state,
158165
@RequestParam String nonce,
159166
@RequestHeader(name = "Authorization", required = false) String auth,
160-
UriComponentsBuilder uriBuilder) throws JOSEException, NoSuchAlgorithmException {
161-
log.info("/authorize scope={} response_type={} client_id={} redirect_uri={}", scope, response_type, client_id, redirect_uri);
167+
UriComponentsBuilder uriBuilder,
168+
HttpServletRequest req) throws JOSEException, NoSuchAlgorithmException {
169+
log.info("called " + AUTHORIZATION_ENDPOINT+" from {}, scope={} response_type={} client_id={} redirect_uri={}",
170+
req.getRemoteHost(), scope, response_type, client_id, redirect_uri);
162171
if (auth == null) {
163172
log.info("user and password not provided");
164173
return response401();
@@ -168,9 +177,8 @@ public ResponseEntity<?> authorize(@RequestParam String client_id,
168177
String password = creds[1];
169178
User user = fakeOidcProperties.getUser();
170179
if (user.getLogname().equals(logname) && user.getPassword().equals(password)) {
171-
log.info("user {} correct", logname);
180+
log.info("password for user {} is correct", logname);
172181
String iss = uriBuilder.replacePath("/").build().encode().toUriString();
173-
String sub = user.getSub();
174182
String access_token = createAccessToken(iss, user, client_id, scope);
175183
String id_token = createIdToken(iss, user, client_id, nonce, access_token);
176184
String url = redirect_uri + "#" +
@@ -189,7 +197,7 @@ public ResponseEntity<?> authorize(@RequestParam String client_id,
189197

190198
private String createAccessToken(String iss, User user, String client_id, String scope) throws JOSEException {
191199
// create JWT claims
192-
Date expiration = new Date(System.currentTimeMillis() + 10 * 3600 * 1000L);
200+
Date expiration = new Date(System.currentTimeMillis() + fakeOidcProperties.getTokenExpirationSeconds() * 1000L);
193201
JWTClaimsSet jwtClaimsSet = new JWTClaimsSet.Builder()
194202
.subject(user.getSub())
195203
.issuer(iss)
@@ -222,7 +230,7 @@ private String createIdToken(String iss, User user, String client_id, String non
222230
.issuer(iss)
223231
.audience(client_id)
224232
.issueTime(new Date())
225-
.expirationTime(new Date(System.currentTimeMillis() + 10 * 3600 * 1000L))
233+
.expirationTime(new Date(System.currentTimeMillis() + fakeOidcProperties.getTokenExpirationSeconds() * 1000L))
226234
.jwtID(UUID.randomUUID().toString())
227235
.claim("nonce", nonce)
228236
.claim("at_hash", encodedHash)

src/main/resources/application.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ server:
1212
key-store: classpath:keystore.p12
1313
key-store-password: password
1414
oidc:
15+
tokenExpirationSeconds: 36000
1516
user:
1617
logname: "perun"
1718
password: "test"

0 commit comments

Comments
 (0)