Skip to content

Commit

Permalink
feat(jans-auth-server): new client config option defaultpromptlogin #979
Browse files Browse the repository at this point in the history


Signed-off-by: Javier Rojas Blum <javier.rojas.blum@gmail.com>
  • Loading branch information
qbert2k authored Mar 5, 2022
1 parent dc42d0f commit 4e3de26
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
*
* @author Javier Rojas Blum
* @author Yuriy Zabrovarnyy
* @version February 10, 2022
* @version March 2, 2022
*/
public class RegisterRequest extends BaseRequest {

Expand Down Expand Up @@ -113,6 +113,7 @@ public class RegisterRequest extends BaseRequest {
private String softwareId;
private String softwareVersion;
private String softwareStatement;
private Boolean defaultPromptLogin;
private BackchannelTokenDeliveryMode backchannelTokenDeliveryMode;
private String backchannelClientNotificationEndpoint;
private AsymmetricSignatureAlgorithm backchannelAuthenticationRequestSigningAlg;
Expand Down Expand Up @@ -1161,6 +1162,14 @@ public void setBackchannelUserCodeParameter(Boolean backchannelUserCodeParameter
this.backchannelUserCodeParameter = backchannelUserCodeParameter;
}

public Boolean getDefaultPromptLogin() {
return defaultPromptLogin;
}

public void setDefaultPromptLogin(Boolean defaultPromptLogin) {
this.defaultPromptLogin = defaultPromptLogin;
}

public String getHttpMethod() {
return httpMethod;
}
Expand Down Expand Up @@ -1383,6 +1392,9 @@ public Map<String, String> getParameters() {
if (backchannelUserCodeParameter != null && backchannelUserCodeParameter) {
parameters.put(BACKCHANNEL_USER_CODE_PARAMETER.toString(), backchannelUserCodeParameter.toString());
}
if (defaultPromptLogin != null) {
parameters.put(DEFAULT_PROMPT_LOGIN.getName(), defaultPromptLogin.toString());
}

// Custom params
if (customAttributes != null && !customAttributes.isEmpty()) {
Expand Down Expand Up @@ -1469,6 +1481,7 @@ public static RegisterRequest fromJson(JSONObject requestObject) throws JSONExce
result.setBackchannelClientNotificationEndpoint(requestObject.optString(BACKCHANNEL_CLIENT_NOTIFICATION_ENDPOINT.toString()));
result.setBackchannelAuthenticationRequestSigningAlg(AsymmetricSignatureAlgorithm.fromString(requestObject.optString(BACKCHANNEL_AUTHENTICATION_REQUEST_SIGNING_ALG.toString())));
result.setBackchannelUserCodeParameter(booleanOrNull(requestObject, BACKCHANNEL_USER_CODE_PARAMETER.toString()));
result.setDefaultPromptLogin(requestObject.optBoolean(DEFAULT_PROMPT_LOGIN.getName()));

return result;
}
Expand Down Expand Up @@ -1680,6 +1693,9 @@ public JSONObject getJSONParameters() throws JSONException {
if (backchannelUserCodeParameter != null) {
parameters.put(BACKCHANNEL_USER_CODE_PARAMETER.toString(), backchannelUserCodeParameter);
}
if (defaultPromptLogin != null) {
parameters.put(DEFAULT_PROMPT_LOGIN.getName(), defaultPromptLogin);
}
// Custom params
if (customAttributes != null && !customAttributes.isEmpty()) {
for (Map.Entry<String, String> entry : customAttributes.entrySet()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text.
*
* Copyright (c) 2020, Janssen Project
*/

package io.jans.as.client.ws.rs;

import io.jans.as.client.*;
import io.jans.as.client.client.Asserter;
import io.jans.as.model.common.ResponseType;
import io.jans.as.model.register.ApplicationType;
import io.jans.as.model.util.StringUtils;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

import java.util.Arrays;
import java.util.List;
import java.util.UUID;

import static io.jans.as.model.register.RegisterRequestParam.*;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;

/**
* @author Javier Rojas Blum
* @version March 3, 2022
*/
public class DefaultPromptLoginTest extends BaseTest {

@Parameters({"userId", "userSecret", "redirectUris", "redirectUri", "sectorIdentifierUri"})
@Test
public void defaultPromptLoginTrue(
final String userId, final String userSecret, final String redirectUris, final String redirectUri,
final String sectorIdentifierUri) {
showTitle("defaultPromptLoginTrue");

List<ResponseType> responseTypes = Arrays.asList(ResponseType.CODE, ResponseType.ID_TOKEN);

// 1. Register client
RegisterRequest registerRequest = new RegisterRequest(ApplicationType.WEB, "jans test app",
StringUtils.spaceSeparatedToList(redirectUris));
registerRequest.setResponseTypes(responseTypes);
registerRequest.setSectorIdentifierUri(sectorIdentifierUri);
registerRequest.setDefaultPromptLogin(true);

RegisterClient registerClient = new RegisterClient(registrationEndpoint);
registerClient.setRequest(registerRequest);
RegisterResponse registerResponse = registerClient.exec();

showClient(registerClient);
Asserter.assertRegisterResponseOk(registerResponse, 201, true);

String clientId = registerResponse.getClientId();
String registrationAccessToken = registerResponse.getRegistrationAccessToken();
String registrationClientUri = registerResponse.getRegistrationClientUri();

// 2. Client Read
RegisterRequest readClientRequest = new RegisterRequest(registrationAccessToken);

RegisterClient readClient = new RegisterClient(registrationClientUri);
readClient.setRequest(readClientRequest);
RegisterResponse readClientResponse = readClient.exec();

showClient(readClient);
assertEquals(readClientResponse.getStatus(), 200, "Unexpected response code: " + readClientResponse.getEntity());
Asserter.assertRegisterResponseOk(readClientResponse, 200, false);

assertNotNull(readClientResponse.getClaims().get(RESPONSE_TYPES.toString()));
assertNotNull(readClientResponse.getClaims().get(REDIRECT_URIS.toString()));
assertNotNull(readClientResponse.getClaims().get(APPLICATION_TYPE.toString()));
assertNotNull(readClientResponse.getClaims().get(CLIENT_NAME.toString()));
assertNotNull(readClientResponse.getClaims().get(ID_TOKEN_SIGNED_RESPONSE_ALG.toString()));
assertNotNull(readClientResponse.getClaims().get(SCOPE.toString()));

// 3. Request authorization
List<String> scopes = Arrays.asList("openid", "profile", "address", "email");
String state = UUID.randomUUID().toString();
String nonce = UUID.randomUUID().toString();

String sessionId;
{
AuthorizationRequest authorizationRequest = new AuthorizationRequest(responseTypes, clientId, scopes,
redirectUri, nonce);
authorizationRequest.setState(state);

AuthorizationResponse authorizationResponse = authenticateResourceOwnerAndGrantAccess(
authorizationEndpoint, authorizationRequest, userId, userSecret);

Asserter.assertAuthorizationResponse(authorizationResponse, responseTypes, true);

sessionId = authorizationResponse.getSessionId();
}

{
AuthorizationRequest authorizationRequest = new AuthorizationRequest(responseTypes, clientId, scopes,
redirectUri, nonce);
authorizationRequest.setState(state);
authorizationRequest.setSessionId(sessionId);

AuthorizationResponse authorizationResponse = authenticateResourceOwnerAndGrantAccess(
authorizationEndpoint, authorizationRequest, userId, userSecret);

Asserter.assertAuthorizationResponse(authorizationResponse, responseTypes, true);
}
}
}
6 changes: 6 additions & 0 deletions jans-auth-server/client/src/test/resources/testng.xml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@
</classes>
</test>

<test name="Default Prompt Login True Test" enabled="true">
<classes>
<class name="io.jans.as.client.ws.rs.DefaultPromptLoginTest"></class>
</classes>
</test>

<test name="Enable Client to restrict JavaScript Origins" enabled="true">
<classes>
<class name="io.jans.as.client.ws.rs.EnableClientToRestrictJavascriptOrigin"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
* @author Yuriy Zabrovarnyy
* @author Javier Rojas Blum
* @version February 10, 2022
* @version March 2, 2022
*/

public enum RegisterRequestParam {
Expand Down Expand Up @@ -347,6 +347,8 @@ public enum RegisterRequestParam {

BACKCHANNEL_USER_CODE_PARAMETER("backchannel_user_code_parameter"),

DEFAULT_PROMPT_LOGIN("default_prompt_login"),

PUBLIC_SUBJECT_IDENTIFIER_ATTRIBUTE("public_subject_identifier_attribute");

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
/**
* @author Yuriy Zabrovarnyy
* @author Javier Rojas Blum
* @version February 10, 2022
* @version March 2, 2022
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class ClientAttributes implements Serializable {
Expand Down Expand Up @@ -92,6 +92,9 @@ public class ClientAttributes implements Serializable {
@JsonProperty("jansSubAttr")
private String publicSubjectIdentifierAttribute;

@JsonProperty("jansDefaultPromptLogin")
private Boolean defaultPromptLogin = false;

public List<String> getRopcScripts() {
if (ropcScripts == null) ropcScripts = new ArrayList<>();
return ropcScripts;
Expand Down Expand Up @@ -293,6 +296,18 @@ public void setPublicSubjectIdentifierAttribute(String publicSubjectIdentifierAt
this.publicSubjectIdentifierAttribute = publicSubjectIdentifierAttribute;
}

public Boolean getDefaultPromptLogin() {
if (defaultPromptLogin == null) {
defaultPromptLogin = false;
}

return defaultPromptLogin;
}

public void setDefaultPromptLogin(Boolean defaultPromptLogin) {
this.defaultPromptLogin = defaultPromptLogin;
}

@Override
public String toString() {
return "ClientAttributes{" +
Expand All @@ -314,6 +329,7 @@ public String toString() {
", authorizationEncryptedResponseAlg=" + authorizationEncryptedResponseAlg +
", authorizationEncryptedResponseEnc=" + authorizationEncryptedResponseEnc +
", publicSubjectIdentifierAttribute=" + publicSubjectIdentifierAttribute +
", defaultPromptLogin=" + defaultPromptLogin +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@
import io.jans.as.model.crypto.binding.TokenBindingMessage;
import io.jans.as.model.crypto.encryption.BlockEncryptionAlgorithm;
import io.jans.as.model.crypto.encryption.KeyEncryptionAlgorithm;
import io.jans.as.model.crypto.signature.SignatureAlgorithm;
import io.jans.as.model.crypto.signature.AlgorithmFamily;
import io.jans.as.model.crypto.signature.SignatureAlgorithm;
import io.jans.as.model.error.ErrorResponseFactory;
import io.jans.as.model.exception.InvalidJwtException;
import io.jans.as.model.jwe.Jwe;
import io.jans.as.model.jwk.Algorithm;
import io.jans.as.model.jwk.JSONWebKeySet;
import io.jans.as.model.jwk.Use;
import io.jans.as.model.jwt.Jwt;
import io.jans.as.model.jwe.Jwe;
import io.jans.as.model.jwt.JwtClaims;
import io.jans.as.model.jwt.JwtClaimName;
import io.jans.as.model.jwt.JwtHeader;
import io.jans.as.model.jwt.JwtHeaderName;
Expand Down Expand Up @@ -100,7 +99,7 @@
* Implementation for request authorization through REST web services.
*
* @author Javier Rojas Blum
* @version February 2, 2022
* @version March 2, 2022
*/
@Path("/")
public class AuthorizeRestWebServiceImpl implements AuthorizeRestWebService {
Expand Down Expand Up @@ -413,7 +412,7 @@ private Response requestAuthorization(
AuthorizeErrorResponseType.INVALID_REQUEST_OBJECT, "",
"The None algorithm in nested JWT is not allowed for FAPI"))
.type(MediaType.APPLICATION_JSON_TYPE).build());
}
}
responseMode = ResponseMode.getByValue(jwr.getClaims().getClaimAsString("response_mode"));
if (responseMode == ResponseMode.JWT) {
redirectUriResponse.getRedirectUri().setResponseMode(ResponseMode.JWT);
Expand Down Expand Up @@ -602,6 +601,12 @@ private Response requestAuthorization(
}
}

if (identity.getSessionId().getState() == SessionIdState.AUTHENTICATED
&& client != null && Boolean.TRUE.equals(client.getAttributes().getDefaultPromptLogin())
&& new Date().getTime() - identity.getSessionId().getAuthenticationTime().getTime() > 200) {
prompts.add(Prompt.LOGIN);
}

if (prompts.contains(Prompt.LOGIN)) {

// workaround for #1030 - remove only authenticated session, for set up acr we set it unauthenticated and then drop in AuthorizeAction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
* @author Javier Rojas Blum
* @author Yuriy Zabrovarnyy
* @author Yuriy Movchan
* @version February 11, 2022
* @version March 2, 2022
*/
@Path("/")
public class RegisterRestWebServiceImpl implements RegisterRestWebService {
Expand Down Expand Up @@ -836,6 +836,10 @@ private void updateClientFromRequestObject(Client client, RegisterRequest reques
client.getAttributes().setPublicSubjectIdentifierAttribute(requestObject.getSubjectIdentifierAttribute());
}

if (requestObject.getDefaultPromptLogin() != null) {
client.getAttributes().setDefaultPromptLogin(requestObject.getDefaultPromptLogin());
}

cibaRegisterClientMetadataService.updateClient(client, requestObject.getBackchannelTokenDeliveryMode(),
requestObject.getBackchannelClientNotificationEndpoint(), requestObject.getBackchannelAuthenticationRequestSigningAlg(),
requestObject.getBackchannelUserCodeParameter());
Expand Down

0 comments on commit 4e3de26

Please sign in to comment.