mirror of
https://github.com/ysoftdevs/oauth-playground-server.git
synced 2026-03-27 11:31:44 +01:00
Device Auth. Grant - redden device token, get token
This commit is contained in:
@@ -3,7 +3,6 @@ package com.ysoft.geecon;
|
|||||||
import com.ysoft.geecon.dto.*;
|
import com.ysoft.geecon.dto.*;
|
||||||
import com.ysoft.geecon.error.OAuthException;
|
import com.ysoft.geecon.error.OAuthException;
|
||||||
import com.ysoft.geecon.repo.ClientsRepo;
|
import com.ysoft.geecon.repo.ClientsRepo;
|
||||||
import com.ysoft.geecon.repo.SecureRandomStrings;
|
|
||||||
import com.ysoft.geecon.repo.SessionsRepo;
|
import com.ysoft.geecon.repo.SessionsRepo;
|
||||||
import com.ysoft.geecon.repo.UsersRepo;
|
import com.ysoft.geecon.repo.UsersRepo;
|
||||||
import io.quarkus.qute.CheckedTemplate;
|
import io.quarkus.qute.CheckedTemplate;
|
||||||
@@ -116,6 +115,7 @@ public class OAuthResource {
|
|||||||
public AccessTokenResponse token(TokenParams params) {
|
public AccessTokenResponse token(TokenParams params) {
|
||||||
return switch (params.getGrantType()) {
|
return switch (params.getGrantType()) {
|
||||||
case "authorization_code" -> redeemAuthorizationCode(params);
|
case "authorization_code" -> redeemAuthorizationCode(params);
|
||||||
|
case "urn:ietf:params:oauth:grant-type:device_code" -> redeemDeviceCode(params);
|
||||||
default -> throw new OAuthException("Unsupported grant type");
|
default -> throw new OAuthException("Unsupported grant type");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -143,22 +143,25 @@ public class OAuthResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private AccessTokenResponse redeemAuthorizationCode(TokenParams params) {
|
private AccessTokenResponse redeemAuthorizationCode(TokenParams params) {
|
||||||
validateClient(params);
|
|
||||||
var session = sessionsRepo.redeemAuthorizationCode(params.getCode())
|
var session = sessionsRepo.redeemAuthorizationCode(params.getCode())
|
||||||
.orElseThrow(() -> new OAuthException("Invalid code"));
|
.orElseThrow(() -> new OAuthException("Invalid code"));
|
||||||
|
validateClient(params, session);
|
||||||
if (!session.validateCodeChallenge(params.getCodeVerifier())) {
|
if (!session.validateCodeChallenge(params.getCodeVerifier())) {
|
||||||
throw new OAuthException("Invalid code verifier");
|
throw new OAuthException("Invalid code verifier");
|
||||||
}
|
}
|
||||||
|
return session.tokens();
|
||||||
|
}
|
||||||
|
|
||||||
String idToken = null;
|
private AccessTokenResponse redeemDeviceCode(TokenParams params) {
|
||||||
|
var session = sessionsRepo.getByAuthorizationCode(params.getDeviceCode())
|
||||||
return new AccessTokenResponse("Bearer",
|
.orElseThrow(() -> new OAuthException("Invalid code"));
|
||||||
8400,
|
validateClient(params, session);
|
||||||
SecureRandomStrings.alphanumeric(50),
|
if (session.tokens() != null) {
|
||||||
session.scope(),
|
sessionsRepo.redeemAuthorizationCode(params.getDeviceCode());
|
||||||
SecureRandomStrings.alphanumeric(50),
|
return session.tokens();
|
||||||
idToken
|
} else {
|
||||||
);
|
throw new OAuthException("Authorization pending");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private User validateUser(String username, String password) {
|
private User validateUser(String username, String password) {
|
||||||
@@ -179,10 +182,10 @@ public class OAuthResource {
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OAuthClient validateClient(TokenParams params) {
|
private OAuthClient validateClient(TokenParams params, AuthorizationSession session) {
|
||||||
var client = clientsRepo.getClient(params.getClientId())
|
var client = clientsRepo.getClient(params.getClientId())
|
||||||
.orElseThrow(() -> new RuntimeException("Not a valid client"));
|
.orElseThrow(() -> new RuntimeException("Not a valid client"));
|
||||||
if (!client.validateRedirectUri(params.getRedirectUri())) {
|
if (!session.validateRedirectUri(params.getRedirectUri())) {
|
||||||
throw new RuntimeException("Invalid redirect URI");
|
throw new RuntimeException("Invalid redirect URI");
|
||||||
}
|
}
|
||||||
if (!client.validateSecret(params.getClientSecret())) {
|
if (!client.validateSecret(params.getClientSecret())) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.ysoft.geecon.dto;
|
|||||||
import com.ysoft.geecon.repo.SecureRandomStrings;
|
import com.ysoft.geecon.repo.SecureRandomStrings;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public record AuthorizationSession(String sessionId,
|
public record AuthorizationSession(String sessionId,
|
||||||
AuthParams params,
|
AuthParams params,
|
||||||
@@ -48,4 +49,7 @@ public record AuthorizationSession(String sessionId,
|
|||||||
return Pkce.validate(params.codeChallengeMethod, params.codeChallenge, codeVerifier);
|
return Pkce.validate(params.codeChallengeMethod, params.codeChallenge, codeVerifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean validateRedirectUri(String redirectUri) {
|
||||||
|
return Objects.equals(params.redirectUri, redirectUri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ public class TokenParams {
|
|||||||
@FormParam("code_verifier")
|
@FormParam("code_verifier")
|
||||||
private String codeVerifier;
|
private String codeVerifier;
|
||||||
|
|
||||||
|
@FormParam("device_code")
|
||||||
|
private String deviceCode;
|
||||||
|
|
||||||
public String getGrantType() {
|
public String getGrantType() {
|
||||||
return grantType;
|
return grantType;
|
||||||
}
|
}
|
||||||
@@ -69,4 +72,12 @@ public class TokenParams {
|
|||||||
public void setCodeVerifier(String codeVerifier) {
|
public void setCodeVerifier(String codeVerifier) {
|
||||||
this.codeVerifier = codeVerifier;
|
this.codeVerifier = codeVerifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDeviceCode() {
|
||||||
|
return deviceCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceCode(String deviceCode) {
|
||||||
|
this.deviceCode = deviceCode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,19 @@ public class DeviceAuthGrantTest {
|
|||||||
when().
|
when().
|
||||||
post("auth/consent")
|
post("auth/consent")
|
||||||
.then().statusCode(200);
|
.then().statusCode(200);
|
||||||
}
|
|
||||||
|
|
||||||
|
given().
|
||||||
|
formParam("grant_type", "urn:ietf:params:oauth:grant-type:device_code").
|
||||||
|
formParam("client_id", "myclient").
|
||||||
|
formParam("device_code", deviceResponse.deviceCode()).
|
||||||
|
when().
|
||||||
|
post("/auth/token")
|
||||||
|
.then()
|
||||||
|
.statusCode(200)
|
||||||
|
.contentType(JSON)
|
||||||
|
.body("token_type", is(notNullValue()))
|
||||||
|
.body("expires_in", is(notNullValue()))
|
||||||
|
.body("access_token", is(notNullValue()))
|
||||||
|
.body("refresh_token", is(notNullValue()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user