Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(jans-auth-server): new client config option defaultpromptlogin #979

Merged
merged 1 commit into from
Mar 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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