mirror of
https://github.com/ysoftdevs/oauth-playground-server.git
synced 2026-01-11 22:41:28 +01:00
id_token
This commit is contained in:
5
pom.xml
5
pom.xml
@@ -50,6 +50,10 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-smallrye-jwt-build</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-junit5</artifactId>
|
<artifactId>quarkus-junit5</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -72,6 +76,7 @@
|
|||||||
<groupId>org.jsoup</groupId>
|
<groupId>org.jsoup</groupId>
|
||||||
<artifactId>jsoup</artifactId>
|
<artifactId>jsoup</artifactId>
|
||||||
<version>1.15.4</version>
|
<version>1.15.4</version>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -14,7 +14,14 @@ public class AuthParams {
|
|||||||
|
|
||||||
public boolean validateResponseType() {
|
public boolean validateResponseType() {
|
||||||
try {
|
try {
|
||||||
return !getResponseTypes().isEmpty();
|
List<ResponseType> responseTypes = getResponseTypes();
|
||||||
|
if (responseTypes.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (responseTypes.contains(ResponseType.id_token)) {
|
||||||
|
return getScopes().contains("openid");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
} catch (IllegalArgumentException exception) {
|
} catch (IllegalArgumentException exception) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.ysoft.geecon.dto;
|
package com.ysoft.geecon.dto;
|
||||||
|
|
||||||
import com.ysoft.geecon.repo.SecureRandomStrings;
|
import com.ysoft.geecon.repo.SecureRandomStrings;
|
||||||
|
import io.smallrye.jwt.build.Jwt;
|
||||||
|
import io.smallrye.jwt.build.JwtClaimsBuilder;
|
||||||
|
import org.eclipse.microprofile.jwt.Claims;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -24,21 +27,38 @@ public record AuthorizationSession(String sessionId,
|
|||||||
}
|
}
|
||||||
|
|
||||||
public AuthorizationSession withGeneratedTokens() {
|
public AuthorizationSession withGeneratedTokens() {
|
||||||
String idToken = null;
|
|
||||||
var tokens = new AccessTokenResponse("Bearer",
|
var tokens = new AccessTokenResponse("Bearer",
|
||||||
8400,
|
expiresIn(),
|
||||||
SecureRandomStrings.alphanumeric(50),
|
SecureRandomStrings.alphanumeric(50),
|
||||||
scope(),
|
scope(),
|
||||||
SecureRandomStrings.alphanumeric(50),
|
SecureRandomStrings.alphanumeric(50),
|
||||||
idToken
|
acceptedScopes.contains("openid") ? idToken() : null
|
||||||
);
|
);
|
||||||
return new AuthorizationSession(sessionId, params, client, user, acceptedScopes, tokens);
|
return new AuthorizationSession(sessionId, params, client, user, acceptedScopes, tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int expiresIn() {
|
||||||
|
return 8400;
|
||||||
|
}
|
||||||
|
|
||||||
public String scope() {
|
public String scope() {
|
||||||
return acceptedScopes == null ? null : String.join(" ", acceptedScopes);
|
return acceptedScopes == null ? null : String.join(" ", acceptedScopes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String idToken() {
|
||||||
|
JwtClaimsBuilder jwt = Jwt.claims()
|
||||||
|
.issuedAt(System.currentTimeMillis() / 1000)
|
||||||
|
.expiresAt(System.currentTimeMillis() / 1000 + expiresIn())
|
||||||
|
.subject(user().id())
|
||||||
|
.audience(client().clientId())
|
||||||
|
.preferredUserName(user().login());
|
||||||
|
|
||||||
|
if (params().nonce != null)
|
||||||
|
jwt.claim(Claims.nonce, params().nonce);
|
||||||
|
|
||||||
|
return jwt.sign();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean validateCodeChallenge(String codeVerifier) {
|
public boolean validateCodeChallenge(String codeVerifier) {
|
||||||
if (params.codeChallengeMethod == null) {
|
if (params.codeChallengeMethod == null) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
package com.ysoft.geecon.dto;
|
package com.ysoft.geecon.dto;
|
||||||
|
|
||||||
|
import com.ysoft.geecon.repo.SecureRandomStrings;
|
||||||
import com.ysoft.geecon.webauthn.WebAuthnCredential;
|
import com.ysoft.geecon.webauthn.WebAuthnCredential;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public record User(String login, String password, List<WebAuthnCredential> credentials) {
|
public record User(String id, String login, String password, List<WebAuthnCredential> credentials) {
|
||||||
|
public User(String login, String password) {
|
||||||
|
this(SecureRandomStrings.alphanumeric(5), login, password, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String login, WebAuthnCredential credential) {
|
||||||
|
this(SecureRandomStrings.alphanumeric(5), login, null, List.of(credential));
|
||||||
|
}
|
||||||
|
|
||||||
public boolean validatePassword(String password) {
|
public boolean validatePassword(String password) {
|
||||||
return this.password != null && this.password.equals(password);
|
return this.password != null && this.password.equals(password);
|
||||||
}
|
}
|
||||||
@@ -26,6 +35,6 @@ public record User(String login, String password, List<WebAuthnCredential> crede
|
|||||||
newCredentials.add(webAuthnCredential);
|
newCredentials.add(webAuthnCredential);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new User(login, password, newCredentials);
|
return new User(id, login, password, newCredentials);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import com.ysoft.geecon.dto.User;
|
|||||||
import jakarta.enterprise.context.ApplicationScoped;
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -33,7 +32,7 @@ public class UsersRepo {
|
|||||||
|
|
||||||
public final void reset() {
|
public final void reset() {
|
||||||
users.clear();
|
users.clear();
|
||||||
register(new User("bob", "Password1", List.of()));
|
register(new User("bob", "Password1"));
|
||||||
register(new User("user", "user", List.of()));
|
register(new User("user", "user"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class WebAuthnSetup implements WebAuthnUserProvider {
|
|||||||
return Uni.createFrom().nullItem();
|
return Uni.createFrom().nullItem();
|
||||||
} else if (existingUser.isEmpty()) {
|
} else if (existingUser.isEmpty()) {
|
||||||
// new user -> register
|
// new user -> register
|
||||||
usersRepo.register(new User(authenticator.getUserName(), null, List.of(credential)));
|
usersRepo.register(new User(authenticator.getUserName(), credential));
|
||||||
return Uni.createFrom().nullItem();
|
return Uni.createFrom().nullItem();
|
||||||
} else {
|
} else {
|
||||||
// in production, we should not add a new credentials to an existing user
|
// in production, we should not add a new credentials to an existing user
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
quarkus.http.cors=true
|
quarkus.http.cors=true
|
||||||
quarkus.http.cors.origins=/.*/
|
quarkus.http.cors.origins=/.*/
|
||||||
quarkus.package.type=uber-jar
|
quarkus.package.type=uber-jar
|
||||||
|
smallrye.jwt.sign.key.location=key.jwk
|
||||||
14
src/main/resources/key.jwk
Normal file
14
src/main/resources/key.jwk
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"p": "8302271HF9MFMVcnFNey7n35KIkxwMpzvimZixHfRTOJCH-YT67FkTIDd1Vle6LI0gfgbKgqrxTRofnyryuVO_3ChIrBQdYHGTrPPHubcgpuFpyMN9ganq7C-aewDIjprygNZTjsjAwKJWvZwMJpOvTVn0biVZ4Iz080iOb4L78",
|
||||||
|
"kty": "RSA",
|
||||||
|
"q": "152Rb5VPGYsoORFMbbjb17cr8cUgipVqooLWHTpzo2wGXampptOqdusm_fnHxw42CxyMvCpD7IcDzumg1dCb5VRZjfwRooLI-pqXNyAnuzpr78ApKCiT8-lkFhNn-NHE-1ctY8Js5HKOUUxP_em8CCCkw33wkRur0HLRvjX7bec",
|
||||||
|
"d": "OgGFO0dui_gXklyLYQ_l9JfQdbwrUuBxYTzv1AZPZ6pY8hs7SrxGr4IrE67zbJEDZgT4ohP2ZTsVABMIfs4J5Gcg213RdQepa05IEXj2rbAUL1LbDAcu6gb-mNDvnBOk0ZQ2l3shY7Q__UWMfUUlZaWEGgO6tQah4K6f6F51cVsggxx9IPsGxOKuocM6UyXW4_DDPnXRc2hFe6mGmnj7TCJ1LL9O59V4G74VVdTO9m2B_BxhsIE-xUqBzP_SfTZ9fQUil_zBtT3Y3UkjeEN70FFaASyKewWRZcEpj6tjZEQ1V0Tq9Yt1CFTww4pb5ctTRBZ5VULynQNBwVXI59jD1Q",
|
||||||
|
"e": "AQAB",
|
||||||
|
"use": "sig",
|
||||||
|
"kid": "MPeUPQwWfMbkj6zB46bbwqd2pdyUtlFHJLFBvyctgTU",
|
||||||
|
"qi": "JNJgYJYEBjWzYb47wU_1Ms4o1TAM5FIseS_dR9Q2sCz7SjjPr3q2p7-v3DoMnc12pXc4tMUWiz8Yn7EtDrvu_3wXmSP4lRM3fD0iaUnjpyyjocMyhFYnwISR81zWEbRgOByVGzeEWqUb3FwDydD9hotPLBOWrM3sqiLT3ETGeRg",
|
||||||
|
"dp": "kOhVLKNR2xjn_zxJ8vqH762jCf_UT1NtXJ_vVDe3s7x-8kLVh56Qz99-9pcpBVKUx4KOirvuYzI1rHtPdfavIvvbtvvJFgBlSxuX1_wMP-t7JxPV0ypWdVe2i9PDT0JwKKDij_o3tQU5SJoOBszsyXyKYfdSnfemcJJHxq4GyIs",
|
||||||
|
"alg": "RS256",
|
||||||
|
"dq": "qtGxlBZVOWZu8m9K_q5ytT7v-LX05vYjKia_nR5e2PzPOksdFgchSN9Z3-KQrJoMpNb0hGpzr6LzmGytOFfx-kjOPleSXQ6CTVBGNq0p7QIG20WBFci4Fogz--1Z9N2z0nApjJxPCtna-Hud8ArKJiI-hoZzHXMvtpAQrUI1NMc",
|
||||||
|
"n": "zRQHMT4aJfWUrFpl6fn-J_2_6hP79Ekkd-eZJ5-YyDeUrFqdRTJw05WWKAzNtdhdO7Tot3aRN5QzXMOBW6pxB2cOMJ8Mwi_maMKa3UgT3jsM_La23AcOZKXJVifOksrUR6lieffPCl3Sh7huoZMS__-xVJzk35QLUJ3_PYeSgpOgoK-wD5Fen2xQhR6Jdg7kZMkPaaqjHSlWhavG5syZ5JEBXPvNXu_Nk0mLzhEq7WFdL3O3cESkdGVGkVFAQI1dTjlKGcT0CQnxmZMKmeIyFgJ6u_qZ0evTpRm5orfVZn-RV2QGilURzwoqInK85J5dW0yHJCxnT9IiHufbcYxoWQ"
|
||||||
|
}
|
||||||
@@ -37,7 +37,7 @@ public class AuthCodeGrantTest {
|
|||||||
@BeforeEach
|
@BeforeEach
|
||||||
void beforeAll() {
|
void beforeAll() {
|
||||||
clientsRepo.register(CLIENT);
|
clientsRepo.register(CLIENT);
|
||||||
usersRepo.register(new User("bob", "password", List.of()));
|
usersRepo.register(new User("bob", "password"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import org.junit.jupiter.api.Test;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||||
@@ -45,7 +44,7 @@ public class DeviceAuthGrantTest {
|
|||||||
@BeforeEach
|
@BeforeEach
|
||||||
void beforeAll() {
|
void beforeAll() {
|
||||||
clientsRepo.register(CLIENT);
|
clientsRepo.register(CLIENT);
|
||||||
usersRepo.register(new User("bob", "password", List.of()));
|
usersRepo.register(new User("bob", "password"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user