Skip to content
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
2 changes: 1 addition & 1 deletion docs/script-catalog/update_token/update-token.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ Jans AS->>RP: return token(s) (Access token, ID token or Refresh Token) reflecti

## Associate an Update Token script to a client (RP) [optional step]

📝 Note: If the Update token script is not associated with a client, then it will be applicable to all clients registered in the Jans Server. Which implies that all tokens obtained using the Jans server will reflect modifications as per the script.
📝 Note: If the Update token script is not associated with a client, then it will not be executed. To run all scripts globally (independent from what is assigned to client) please set global AS configuration property `runAllUpdateTokenScripts` is set to `true`. Which implies that all tokens obtained using the Jans server will reflect modifications as per the script.
<br/>
To Associate an Update Token script to a client (RP), execute the command below with appropriate values for:
- inum of the client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,9 @@ public class AppConfiguration implements Configuration {
@DocProperty(description = "Boolean value specifying whether to disable prompt=consent", defaultValue = "false")
private Boolean disablePromptConsent = false;

@DocProperty(description = "Boolean value specifying whether to run all Update Token scripts", defaultValue = "false")
private Boolean runAllUpdateTokenScripts = false;

@DocProperty(description = "The lifetime of Logout Status JWT. If not set falls back to 1 day", defaultValue = "86400")
private Integer logoutStatusJwtLifetime = DEFAULT_LOGOUT_STATUS_JWT_LIFETIME;

Expand Down Expand Up @@ -1442,6 +1445,15 @@ public void setDisablePromptConsent(Boolean disablePromptConsent) {
this.disablePromptConsent = disablePromptConsent;
}

public Boolean getRunAllUpdateTokenScripts() {
if (runAllUpdateTokenScripts == null) runAllUpdateTokenScripts = false;
return runAllUpdateTokenScripts;
}

public void setRunAllUpdateTokenScripts(Boolean runAllUpdateTokenScripts) {
this.runAllUpdateTokenScripts = runAllUpdateTokenScripts;
}

public Boolean getIncludeSidInResponse() {
if (includeSidInResponse == null) includeSidInResponse = false;
return includeSidInResponse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package io.jans.as.server.service.external;

import com.google.common.collect.Lists;
import io.jans.as.model.configuration.AppConfiguration;
import io.jans.as.model.token.JsonWebResponse;
import io.jans.as.server.model.common.AccessToken;
import io.jans.as.server.model.common.RefreshToken;
Expand All @@ -16,19 +17,24 @@
import io.jans.model.custom.script.type.token.UpdateTokenType;
import io.jans.service.custom.script.ExternalScriptService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.WebApplicationException;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.function.Function;

import static org.apache.commons.lang3.BooleanUtils.isTrue;

/**
* @author Yuriy Movchan
*/
@ApplicationScoped
public class ExternalUpdateTokenService extends ExternalScriptService {

private static final long serialVersionUID = -1033475075863270259L;
@Inject
private AppConfiguration appConfiguration;

public ExternalUpdateTokenService() {
super(CustomScriptType.UPDATE_TOKEN);
Expand Down Expand Up @@ -117,9 +123,20 @@ public int getRefreshTokenLifetimeInSeconds(ExternalUpdateTokenContext context)
}

@NotNull
private List<CustomScriptConfiguration> getScripts(@NotNull ExternalUpdateTokenContext context) {
if (customScriptConfigurations == null || customScriptConfigurations.isEmpty() || context.getClient() == null) {
log.trace("No UpdateToken scripts or client is null.");
protected List<CustomScriptConfiguration> getScripts(@NotNull ExternalUpdateTokenContext context) {
List<CustomScriptConfiguration> customScriptConfigurations = getCustomScriptConfigurations();
if (customScriptConfigurations == null || customScriptConfigurations.isEmpty()) {
log.trace("No UpdateToken scripts.");
return Lists.newArrayList();
}

if (isTrue(appConfiguration.getRunAllUpdateTokenScripts())) {
log.trace("Run all UpdateToken scripts.");
return customScriptConfigurations;
}

if (context.getClient() == null) {
log.trace("No client.");
return Lists.newArrayList();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class ExternalScriptContext extends io.jans.service.external.context.Exte

private static final Logger log = LoggerFactory.getLogger(ExternalScriptContext.class);

private final PersistenceEntryManager persistenceEntryManager;
private PersistenceEntryManager persistenceEntryManager;

private ExecutionContext executionContext;

Expand All @@ -51,7 +51,6 @@ public ExternalScriptContext(HttpServletRequest httpRequest) {

public ExternalScriptContext(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
super(httpRequest, httpResponse);
this.persistenceEntryManager = ServerUtil.getLdapManager();
}

public static ExternalScriptContext of(ExecutionContext executionContext) {
Expand All @@ -75,6 +74,13 @@ public AuthzDetail getAuthzDetail() {
}

public PersistenceEntryManager getPersistenceEntryManager() {
if (persistenceEntryManager == null) {
synchronized (this) {
if (persistenceEntryManager == null) {
persistenceEntryManager = ServerUtil.getLdapManager();
}
}
}
return persistenceEntryManager;
}

Expand All @@ -89,7 +95,7 @@ public boolean isInNetwork(String cidrNotation) {

protected CustomEntry getEntryByDn(String dn, String... ldapReturnAttributes) {
try {
return persistenceEntryManager.find(dn, CustomEntry.class, ldapReturnAttributes);
return getPersistenceEntryManager().find(dn, CustomEntry.class, ldapReturnAttributes);
} catch (EntryPersistenceException epe) {
log.error("Failed to find entry '{}'", dn);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,21 @@ public class ExternalUpdateTokenContext extends ExternalScriptContext {

private static final Logger log = LoggerFactory.getLogger(ExternalUpdateTokenContext.class);

private final Client client;
private Client client;
private AuthorizationGrant grant;

private final AppConfiguration appConfiguration;
private final AttributeService attributeService;
private AppConfiguration appConfiguration;
private AttributeService attributeService;

private CustomScriptConfiguration script;
@Nullable
private ExecutionContext executionContext;
private JwtSigner jwtSigner;

public ExternalUpdateTokenContext() {
super((HttpServletRequest) null);
}

public ExternalUpdateTokenContext(HttpServletRequest httpRequest, AuthorizationGrant grant,
Client client, AppConfiguration appConfiguration, AttributeService attributeService) {
super(httpRequest);
Expand Down Expand Up @@ -116,6 +120,10 @@ public Client getClient() {
return client;
}

public void setClient(Client client) {
this.client = client;
}

public AuthorizationGrant getGrant() {
return grant;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package io.jans.as.server.service.external;

import io.jans.as.common.model.registration.Client;
import io.jans.as.model.configuration.AppConfiguration;
import io.jans.as.model.error.ErrorResponseFactory;
import io.jans.as.server.service.external.context.ExternalUpdateTokenContext;
import io.jans.model.custom.script.conf.CustomScriptConfiguration;
import io.jans.model.custom.script.model.CustomScript;
import io.jans.model.custom.script.type.token.DummyUpdateTokenType;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.testng.MockitoTestNGListener;
import org.slf4j.Logger;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.when;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;

@Listeners(MockitoTestNGListener.class)
public class ExternalUpdateTokenServiceTest {

@Spy
@InjectMocks
private ExternalUpdateTokenService externalUpdateTokenService;

@Mock
private Logger log;

@Mock
private AppConfiguration appConfiguration;

@Mock
private ErrorResponseFactory errorResponseFactory;

@Test
public void getScripts_whenNoScripts_shouldReturnEmptyList() {
assertTrue(externalUpdateTokenService.getScripts(new ExternalUpdateTokenContext()).isEmpty());
}

@Test
public void getScripts_whenScriptsPresentAndRunAllIsTrue_shouldReturnNonEmptyList() {
List<CustomScriptConfiguration> scripts = new ArrayList<>();
scripts.add(new CustomScriptConfiguration(new CustomScript("", "", ""), new DummyUpdateTokenType(), new HashMap<>()));

when(appConfiguration.getRunAllUpdateTokenScripts()).thenReturn(true);
when(externalUpdateTokenService.getCustomScriptConfigurations()).thenReturn(scripts);

assertFalse(externalUpdateTokenService.getScripts(new ExternalUpdateTokenContext()).isEmpty());
}

@Test
public void getScripts_whenScriptsPresentAndRunAllIsFalse_shouldReturnEmptyList() {
List<CustomScriptConfiguration> scripts = new ArrayList<>();
scripts.add(new CustomScriptConfiguration(new CustomScript("", "", ""), new DummyUpdateTokenType(), new HashMap<>()));

when(appConfiguration.getRunAllUpdateTokenScripts()).thenReturn(false);
when(externalUpdateTokenService.getCustomScriptConfigurations()).thenReturn(scripts);

assertTrue(externalUpdateTokenService.getScripts(new ExternalUpdateTokenContext()).isEmpty());
}

@Test
public void getScripts_whenScriptsPresentAndRunAllIsFalseAndClientHasNoScripts_shouldReturnEmptyList() {
List<CustomScriptConfiguration> scripts = new ArrayList<>();
scripts.add(new CustomScriptConfiguration(new CustomScript("", "", ""), new DummyUpdateTokenType(), new HashMap<>()));

when(appConfiguration.getRunAllUpdateTokenScripts()).thenReturn(false);
when(externalUpdateTokenService.getCustomScriptConfigurations()).thenReturn(scripts);

ExternalUpdateTokenContext context = new ExternalUpdateTokenContext();
context.setClient(new Client());

assertTrue(externalUpdateTokenService.getScripts(context).isEmpty());
}

@Test
public void getScripts_whenScriptsPresentAndRunAllIsFalseAndClientHasScripts_shouldReturnNonEmptyList() {
List<CustomScriptConfiguration> scripts = new ArrayList<>();
scripts.add(new CustomScriptConfiguration(new CustomScript("dummy", "", ""), new DummyUpdateTokenType(), new HashMap<>()));

when(appConfiguration.getRunAllUpdateTokenScripts()).thenReturn(false);
when(externalUpdateTokenService.getCustomScriptConfigurations()).thenReturn(scripts);
when(externalUpdateTokenService.getCustomScriptConfigurationsByDns(anyList())).thenReturn(scripts);

Client client = new Client();
client.getAttributes().setUpdateTokenScriptDns(List.of("dummy"));

ExternalUpdateTokenContext context = new ExternalUpdateTokenContext();
context.setClient(client);

assertFalse(externalUpdateTokenService.getScripts(context).isEmpty());
}
}