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-config-api): added scope DN validation while client creation #1293

Merged
merged 5 commits into from
May 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 @@ -23,7 +23,6 @@
import jakarta.ws.rs.core.UriInfo;
import jakarta.ws.rs.ext.Provider;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;

/**
Expand Down Expand Up @@ -78,7 +77,7 @@ public void filter(ContainerRequestContext context) {

log.info("\n\n\n AuthorizationFilter::filter() - Config Api OAuth Valdation Enabled");
if (!isTokenBasedAuthentication(authorizationHeader)) {
abortWithUnauthorized(context);
abortWithUnauthorized(context, "ONLY TOKEN BASED AUTHORIZATION IS SUPPORTED!");
log.info("======ONLY TOKEN BASED AUTHORIZATION IS SUPPORTED======================");
return;
}
Expand All @@ -93,7 +92,7 @@ public void filter(ContainerRequestContext context) {
log.info("======AUTHORIZATION GRANTED===========================================");
} catch (Exception ex) {
log.error("======AUTHORIZATION FAILED ===========================================", ex);
abortWithUnauthorized(context);
abortWithUnauthorized(context, ex.getMessage());
}

}
Expand All @@ -103,8 +102,8 @@ private boolean isTokenBasedAuthentication(String authorizationHeader) {
&& authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_SCHEME.toLowerCase() + " ");
}

private void abortWithUnauthorized(ContainerRequestContext requestContext) {
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
private void abortWithUnauthorized(ContainerRequestContext requestContext, String errMsg) {
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity(errMsg)
.header(HttpHeaders.WWW_AUTHENTICATE, AUTHENTICATION_SCHEME).build());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@
import io.jans.as.common.model.registration.Client;
import io.jans.as.common.service.common.EncryptionService;
import io.jans.as.common.service.common.InumService;
import io.jans.as.persistence.model.Scope;
import io.jans.configapi.core.rest.ProtectedApi;
import io.jans.configapi.core.model.SearchRequest;
import io.jans.configapi.service.auth.ClientService;
import io.jans.configapi.service.auth.ConfigurationService;
import io.jans.configapi.service.auth.ScopeService;
import io.jans.configapi.util.ApiAccessConstants;
import io.jans.configapi.util.ApiConstants;
import io.jans.configapi.util.AttributeNames;
import io.jans.configapi.util.AuthUtil;
import io.jans.configapi.core.util.Jackson;
import io.jans.orm.PersistenceEntryManager;
import io.jans.orm.exception.EntryPersistenceException;
import io.jans.orm.model.PagedResult;
import io.jans.util.StringHelper;
import io.jans.util.security.StringEncrypter.EncryptionException;
Expand All @@ -36,8 +40,6 @@
import java.util.List;
import java.util.UUID;

import org.slf4j.Logger;

/**
* @author Mougang T.Gasmyr
*
Expand All @@ -51,9 +53,6 @@ public class ClientsResource extends ConfigBaseResource {

private static final String OPENID_CONNECT_CLIENT = "openid connect client";

@Inject
Logger logger;

@Inject
ClientService clientService;

Expand All @@ -65,6 +64,12 @@ public class ClientsResource extends ConfigBaseResource {

@Inject
EncryptionService encryptionService;

@Inject
AuthUtil authUtil;

@Inject
ScopeService scopeService;

@GET
@ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_READ_ACCESS })
Expand Down Expand Up @@ -112,6 +117,10 @@ public Response createOpenIdConnect(@Valid Client client) throws EncryptionExcep
client.setClientId(inum);
}
checkNotNull(client.getClientName(), AttributeNames.DISPLAY_NAME);

//scope validation
checkScopeFormat(client);

String clientSecret = client.getClientSecret();

if (StringHelper.isEmpty(clientSecret)) {
Expand All @@ -121,7 +130,7 @@ public Response createOpenIdConnect(@Valid Client client) throws EncryptionExcep
client.setClientSecret(encryptionService.encrypt(clientSecret));
client.setDn(clientService.getDnForClient(inum));
client.setDeletable(client.getClientSecretExpiresAt() != null);
ignoreCustomObjectClassesForNonLDAP(client);
ignoreCustomObjectClassesForNonLDAP(client);

logger.debug("Final Client details to be added - client:{}", client);
clientService.addClient(client);
Expand All @@ -142,6 +151,10 @@ public Response updateClient(@Valid Client client) throws EncryptionException {
checkNotNull(client.getClientName(), AttributeNames.DISPLAY_NAME);
Client existingClient = clientService.getClientByInum(inum);
checkResourceNotNull(existingClient, OPENID_CONNECT_CLIENT);

//scope validation
checkScopeFormat(client);

client.setClientId(existingClient.getClientId());
client.setBaseDn(clientService.getDnForClient(inum));
client.setDeletable(client.getExpirationDate() != null);
Expand Down Expand Up @@ -233,6 +246,57 @@ private Client ignoreCustomObjectClassesForNonLDAP(Client client) {
return client;
}


private Client checkScopeFormat(Client client) {
if (client == null) {
return client;
}

// check scope
logger.debug("Checking client.getScopes():{}", client.getScopes());
if (client.getScopes() == null || client.getScopes().length == 0) {
return client;
}

List<String> validScopes = new ArrayList<>();
List<String> invalidScopes = new ArrayList<>();

for (String scope : client.getScopes()) {
logger.debug("Is scope:{} valid:{}", scope, authUtil.isValidDn(scope));
List<Scope> scopes = new ArrayList<>();
if (authUtil.isValidDn(scope)) {
Scope scp = findScopeByDn(scope);
if(scp!=null) {
scopes.add(scp);
}
} else {
scopes = scopeService.searchScopesById(scope);
}
logger.debug("Scopes from DB - {}'", scopes);
if (!scopes.isEmpty()) {
validScopes.add(scopes.get(0).getDn());
} else {
invalidScopes.add(scope);
}
}
logger.debug("Scope validation result - validScopes:{}, invalidScopes:{} ", validScopes, invalidScopes);

if (!invalidScopes.isEmpty()) {
thorwBadRequestException("Invalid scope in request -> " + invalidScopes.toString());
}

// reset scopes
if (!validScopes.isEmpty()) {
String[] scopeArr = validScopes.stream().toArray(String[]::new);
client.setScopes(scopeArr);
}
return client;
}

private Scope findScopeByDn(String scopeDn) {
try {
return scopeService.getScopeByDn(scopeDn);
} catch (EntryPersistenceException e) {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ public List<Scope> searchScopesById(String jsId) {
return new ArrayList<>();
}
}

public Scope getScopeByDn(String dn) {
return persistenceEntryManager.find(Scope.class, dn);
}

public List<Scope> searchScopes(String pattern, int sizeLimit, String scopeType) {
String[] targetArray = new String[] { pattern };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.jans.configapi.util;

import com.unboundid.ldap.sdk.DN;
import io.jans.as.client.TokenResponse;
import io.jans.as.common.model.registration.Client;
import io.jans.as.common.service.common.EncryptionService;
Expand Down Expand Up @@ -391,6 +392,15 @@ public List<Field> getAllFields(List<Field> fields, Class<?> type) {
log.debug("Final fields:{} of type:{} ", fields, type);
return fields;
}

public boolean isValidDn(String dn) {
return isValidDn(dn, false);
}


public boolean isValidDn(String dn, boolean strictNameChecking) {
return DN.isValidDN(dn, strictNameChecking);
}



Expand Down