Skip to content

Commit

Permalink
feat(jans-auth-server): authz challenge should not require client_id …
Browse files Browse the repository at this point in the history
…and acr_values if valid device_session is provided #6867 (#7704)

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>
  • Loading branch information
yuriyz committed Feb 13, 2024
1 parent ea90e2a commit 76b63e5
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 11 deletions.
19 changes: 19 additions & 0 deletions docs/admin/auth-server/endpoints/authorization-challenge.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,16 @@ Full sample script can be found [here](../../../script-catalog/authorization_cha

Device session is optional. AS does not return it by default.
It's possible to pass in request `use_device_session=true` which makes AS return it in error response.
If it is desired to use `device_session` and don't pass `client_id` (or other parameters) in next request,
it should be put in attributes of `device_session` object.

Example
```java
String clientId = context.getHttpRequest().getParameter("client_id");
deviceSessionObject.getAttributes().getAttributes().put("client_id", clientId);
```

Full sample script can be found [here](../../../script-catalog/authorization_challenge/AuthorizationChallenge.java)

## Multi-step example

Expand Down Expand Up @@ -224,6 +233,16 @@ In custom script it's easy to code what data has to be kept in `device_session`.
if (StringUtils.isNotBlank(otp)) {
deviceSessionObject.getAttributes().getAttributes().put(OTP_PARAMETER, otp);
}
String clientId = context.getHttpRequest().getParameter("client_id");
if (StringUtils.isNotBlank(clientId)) {
deviceSessionObject.getAttributes().getAttributes().put("client_id", clientId);
}
String acrValues = context.getHttpRequest().getParameter("acr_values");
if (StringUtils.isNotBlank(acrValues)) {
deviceSessionObject.getAttributes().getAttributes().put("acr_values", acrValues);
}
if (newSave) {
deviceSessionService.persist(deviceSessionObject);
Expand Down
20 changes: 20 additions & 0 deletions docs/admin/developer/scripts/authorization-challenge.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,16 @@ public class AuthorizationChallenge implements AuthorizationChallengeType {
if (StringUtils.isNotBlank(password)) {
deviceSessionObject.getAttributes().getAttributes().put(PASSWORD_PARAMETER, password);
}

String clientId = context.getHttpRequest().getParameter("client_id");
if (StringUtils.isNotBlank(clientId)) {
deviceSessionObject.getAttributes().getAttributes().put("client_id", clientId);
}

String acrValues = context.getHttpRequest().getParameter("acr_values");
if (StringUtils.isNotBlank(acrValues)) {
deviceSessionObject.getAttributes().getAttributes().put("acr_values", acrValues);
}

if (newSave) {
deviceSessionService.persist(deviceSessionObject);
Expand Down Expand Up @@ -392,6 +402,16 @@ public class AuthorizationChallenge implements AuthorizationChallengeType {
if (StringUtils.isNotBlank(otp)) {
deviceSessionObject.getAttributes().getAttributes().put(OTP_PARAMETER, otp);
}
String clientId = context.getHttpRequest().getParameter("client_id");
if (StringUtils.isNotBlank(clientId)) {
deviceSessionObject.getAttributes().getAttributes().put("client_id", clientId);
}
String acrValues = context.getHttpRequest().getParameter("acr_values");
if (StringUtils.isNotBlank(acrValues)) {
deviceSessionObject.getAttributes().getAttributes().put("acr_values", acrValues);
}
if (newSave) {
deviceSessionService.persist(deviceSessionObject);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,16 @@ private DeviceSession prepareDeviceSession(ExternalScriptContext context, Device
deviceSessionObject.getAttributes().getAttributes().put(PASSWORD_PARAMETER, password);
}

String clientId = context.getHttpRequest().getParameter("client_id");
if (StringUtils.isNotBlank(clientId)) {
deviceSessionObject.getAttributes().getAttributes().put("client_id", clientId);
}

String acrValues = context.getHttpRequest().getParameter("acr_values");
if (StringUtils.isNotBlank(acrValues)) {
deviceSessionObject.getAttributes().getAttributes().put("acr_values", acrValues);
}

if (newSave) {
deviceSessionService.persist(deviceSessionObject);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ private DeviceSession prepareDeviceSession(ExternalScriptContext context, Device
deviceSessionObject.getAttributes().getAttributes().put(OTP_PARAMETER, otp);
}

String clientId = context.getHttpRequest().getParameter("client_id");
if (StringUtils.isNotBlank(clientId)) {
deviceSessionObject.getAttributes().getAttributes().put("client_id", clientId);
}

String acrValues = context.getHttpRequest().getParameter("acr_values");
if (StringUtils.isNotBlank(acrValues)) {
deviceSessionObject.getAttributes().getAttributes().put("acr_values", acrValues);
}

if (newSave) {
deviceSessionService.persist(deviceSessionObject);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.collect.Maps;
import io.jans.as.common.model.common.User;
import io.jans.as.common.model.registration.Client;
import io.jans.as.common.model.session.DeviceSession;
import io.jans.as.common.model.session.SessionId;
import io.jans.as.model.authorize.AuthorizationChallengeResponse;
import io.jans.as.model.authorize.AuthorizeErrorResponseType;
Expand Down Expand Up @@ -114,7 +115,25 @@ public void prepareAuthzRequest(AuthzRequest authzRequest) {
authzRequest.setScope(ServerUtil.urlDecode(authzRequest.getScope()));

if (StringUtils.isNotBlank(authzRequest.getDeviceSession())) {
authzRequest.setDeviceSessionObject(deviceSessionService.getDeviceSession(authzRequest.getDeviceSession()));
final DeviceSession deviceSession = deviceSessionService.getDeviceSession(authzRequest.getDeviceSession());

authzRequest.setDeviceSessionObject(deviceSession);
if (deviceSession != null) {
final Map<String, String> deviceSessionAttributes = deviceSession.getAttributes().getAttributes();

final String clientId = deviceSessionAttributes.get("client_id");
if (StringUtils.isNotBlank(clientId) && StringUtils.isBlank(authzRequest.getClientId())) {
authzRequest.setClientId(clientId);
}

String acrValues = deviceSession.getAttributes().getAcrValues();
if (StringUtils.isBlank(acrValues)) {
acrValues = deviceSessionAttributes.get("acr_values");
}
if (StringUtils.isNotBlank(acrValues) && StringUtils.isBlank(authzRequest.getAcrValues())) {
authzRequest.setAcrValues(acrValues);
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package io.jans.as.server.authorize.ws.rs;

import io.jans.as.common.model.session.DeviceSession;
import io.jans.as.model.configuration.AppConfiguration;
import io.jans.as.model.error.ErrorResponseFactory;
import io.jans.as.server.audit.ApplicationAuditLogger;
import io.jans.as.server.model.authorize.ScopeChecker;
import io.jans.as.server.model.common.AuthorizationGrantList;
import io.jans.as.server.security.Identity;
import io.jans.as.server.service.CookieService;
import io.jans.as.server.service.RequestParameterService;
import io.jans.as.server.service.SessionIdService;
import io.jans.as.server.service.external.ExternalAuthorizationChallengeService;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.slf4j.Logger;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;

import static org.mockito.Mockito.when;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNull;

/**
* @author Yuriy Z
*/
@Listeners(MockitoTestNGListener.class)
public class AuthorizationChallengeServiceTest {

@InjectMocks
private AuthorizationChallengeService authorizationChallengeService;

@Mock
private Logger log;

@Mock
private AuthzRequestService authzRequestService;

@Mock
private ApplicationAuditLogger applicationAuditLogger;

@Mock
private AuthorizeRestWebServiceValidator authorizeRestWebServiceValidator;

@Mock
private ScopeChecker scopeChecker;

@Mock
private AuthorizationGrantList authorizationGrantList;

@Mock
private AuthorizationChallengeValidator authorizationChallengeValidator;

@Mock
private ExternalAuthorizationChallengeService externalAuthorizationChallengeService;

@Mock
private ErrorResponseFactory errorResponseFactory;

@Mock
private DeviceSessionService deviceSessionService;

@Mock
private Identity identity;

@Mock
private SessionIdService sessionIdService;

@Mock
private AppConfiguration appConfiguration;

@Mock
private RequestParameterService requestParameterService;

@Mock
private CookieService cookieService;

@Test
public void prepareAuthzRequest_whenClientIdStoredInAttributes_shouldPopulateAuthzRequest() {
final String deviceSessionId = "device_session_1234";

final DeviceSession deviceSession = new DeviceSession();
deviceSession.setId(deviceSessionId);
deviceSession.getAttributes().getAttributes().put("client_id", "1234");

final AuthzRequest authzRequest = new AuthzRequest();
authzRequest.setDeviceSession(deviceSessionId);
assertNull(authzRequest.getClientId());

when(deviceSessionService.getDeviceSession(deviceSessionId)).thenReturn(deviceSession);

authorizationChallengeService.prepareAuthzRequest(authzRequest);
assertEquals("1234", authzRequest.getClientId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

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

import com.google.common.collect.Lists;
import io.jans.as.client.EndSessionRequest;
import io.jans.as.client.RegisterRequest;
import io.jans.as.model.authorize.AuthorizeResponseParam;
Expand All @@ -18,26 +17,22 @@
import io.jans.as.model.util.StringUtils;
import io.jans.as.server.BaseTest;
import io.jans.as.server.model.TClientService;
import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import static org.testng.Assert.*;

/**
* @author Yuriy Zabrovarnyy
Expand All @@ -57,7 +52,7 @@ public void requestEndSessionStep1(final String redirectUris, final String postL
io.jans.as.client.RegisterRequest registerRequest = new RegisterRequest(ApplicationType.WEB, "jans test app", StringUtils.spaceSeparatedToList(redirectUris));
registerRequest.setResponseTypes(Arrays.asList(ResponseType.TOKEN, ResponseType.ID_TOKEN));
registerRequest.setPostLogoutRedirectUris(Arrays.asList(postLogoutRedirectUri));
registerRequest.setBackchannelLogoutUri(Lists.newArrayList(postLogoutRedirectUri));
registerRequest.setBackchannelLogoutUri(postLogoutRedirectUri);
registerRequest.addCustomAttribute("jansTrustedClnt", "true");

registerResponse = TClientService.register(registerRequest, getApiTagetURL(url));
Expand Down
1 change: 1 addition & 0 deletions jans-auth-server/server/src/test/resources/testng.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<class name="io.jans.as.server.authorize.ws.rs.AuthorizationChallengeValidatorTest" />
<class name="io.jans.as.server.authorize.ws.rs.AuthzRequestTest" />
<class name="io.jans.as.server.authorize.ws.rs.AuthzDetailsServiceTest" />
<class name="io.jans.as.server.authorize.ws.rs.AuthorizationChallengeServiceTest" />

<!-- REVOKE -->
<class name="io.jans.as.server.revoke.RevokeRestWebServiceImplTest" />
Expand Down

0 comments on commit 76b63e5

Please sign in to comment.