Skip to content

Commit

Permalink
Merge branch 'develop' into cern-lifecycle-restore
Browse files Browse the repository at this point in the history
  • Loading branch information
enricovianello authored Oct 5, 2023
2 parents b6c9fda + bbfeddb commit 59b0b05
Show file tree
Hide file tree
Showing 43 changed files with 1,668 additions and 204 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/sonar.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
name: Sonar analysis

on:
on:
push:
branches:
- develop
pull_request:
types: [opened, edited, reopened, synchronize]

Expand Down Expand Up @@ -28,7 +31,7 @@ jobs:
- name: Sonar analysis
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN_VIANELLO }}
run: mvn -B -U install sonar:sonar
-Dsonar.projectKey=indigo-iam_iam
-Dsonar.organization=indigo-iam
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# INDIGO Identity and Access Management (IAM) service

[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.3496834.svg)](https://doi.org/10.5281/zenodo.3496834)
[![travis-build-tatus](https://travis-ci.org/indigo-iam/iam.svg?branch=develop)](https://travis-ci.org/indigo-iam/iam)
[![build & packaging](https://github.com/indigo-iam/iam/actions/workflows/maven.yml/badge.svg?branch=master&event=push)](https://github.com/indigo-iam/iam/actions/workflows/maven.yml)
[![sonarqube-qg](https://sonarcloud.io/api/project_badges/measure?project=indigo-iam_iam&metric=alert_status)](https://sonarcloud.io/dashboard?id=indigo-iam_iam)
[![sonarqube-coverage](https://sonarcloud.io/api/project_badges/measure?project=indigo-iam_iam&metric=coverage)](https://sonarcloud.io/dashboard?id=indigo-iam_iam)
[![sonarqube-maintainability](https://sonarcloud.io/api/project_badges/measure?project=indigo-iam_iam&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=indigo-iam_iam)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import it.infn.mw.iam.api.common.client.RegisteredClientDTO;
import it.infn.mw.iam.api.common.client.TokenEndpointAuthenticationMethod;
import it.infn.mw.iam.config.IamProperties;
import it.infn.mw.iam.config.client_registration.ClientRegistrationProperties;

@Component
public class ClientConverter {
Expand All @@ -46,11 +47,14 @@ public class ClientConverter {

private final String clientRegistrationBaseUrl;

private final ClientRegistrationProperties clientProperties;

@Autowired
public ClientConverter(IamProperties properties) {
public ClientConverter(IamProperties properties, ClientRegistrationProperties clientProperties) {
this.iamProperties = properties;
clientRegistrationBaseUrl =
String.format("%s%s", iamProperties.getBaseUrl(), ClientRegistrationApiController.ENDPOINT);
this.clientProperties = clientProperties;
}

private <T> Set<T> cloneSet(Set<T> stringSet) {
Expand All @@ -67,18 +71,17 @@ public ClientDetailsEntity entityFromClientManagementRequest(RegisteredClientDTO
ClientDetailsEntity client = entityFromRegistrationRequest(dto);

if (dto.getAccessTokenValiditySeconds() != null) {
if (dto.getAccessTokenValiditySeconds() <= 0) {
client.setAccessTokenValiditySeconds(null);
} else {
client.setAccessTokenValiditySeconds(dto.getAccessTokenValiditySeconds());
}
client.setAccessTokenValiditySeconds(dto.getAccessTokenValiditySeconds());
} else {
client.setAccessTokenValiditySeconds(
clientProperties.getClientDefaults().getDefaultAccessTokenValiditySeconds());
}

if (dto.getRefreshTokenValiditySeconds() != null) {
if (dto.getRefreshTokenValiditySeconds() <= 0) {
client.setRefreshTokenValiditySeconds(null);
} else {
client.setRefreshTokenValiditySeconds(dto.getRefreshTokenValiditySeconds());
}
client.setRefreshTokenValiditySeconds(dto.getRefreshTokenValiditySeconds());
} else {
client.setRefreshTokenValiditySeconds(
clientProperties.getClientDefaults().getDefaultRefreshTokenValiditySeconds());
}

if (dto.getIdTokenValiditySeconds() != null) {
Expand Down Expand Up @@ -193,19 +196,16 @@ public ClientDetailsEntity entityFromRegistrationRequest(RegisteredClientDTO dto

client.setLogoUri(dto.getLogoUri());
client.setPolicyUri(dto.getPolicyUri());

client.setRedirectUris(cloneSet(dto.getRedirectUris()));

client.setScope(cloneSet(dto.getScope()));
client.setGrantTypes(new HashSet<>());

client.setGrantTypes(new HashSet<>());

if (!isNull(dto.getGrantTypes())) {
client.setGrantTypes(
dto.getGrantTypes()
.stream()
.map(AuthorizationGrantType::getGrantType)
.collect(toSet()));
dto.getGrantTypes().stream().map(AuthorizationGrantType::getGrantType).collect(toSet()));
}

if (dto.getScope().contains("offline_access")) {
Expand All @@ -231,6 +231,11 @@ public ClientDetailsEntity entityFromRegistrationRequest(RegisteredClientDTO dto
client.setCodeChallengeMethod(pkceAlgo);
}

client.setAccessTokenValiditySeconds(
clientProperties.getClientDefaults().getDefaultAccessTokenValiditySeconds());
client.setRefreshTokenValiditySeconds(
clientProperties.getClientDefaults().getDefaultRefreshTokenValiditySeconds());

return client;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,39 +58,23 @@ public ClientDetailsEntity setupClientDefaults(ClientDetailsEntity client) {
client.setClientId(UUID.randomUUID().toString());
}

client.setAccessTokenValiditySeconds(
properties.getClientDefaults().getDefaultAccessTokenValiditySeconds());

client
.setIdTokenValiditySeconds(properties.getClientDefaults().getDefaultIdTokenValiditySeconds());

client.setDeviceCodeValiditySeconds(
properties.getClientDefaults().getDefaultDeviceCodeValiditySeconds());

final int rtSecs = properties.getClientDefaults().getDefaultRefreshTokenValiditySeconds();

if (rtSecs < 0) {
client.setRefreshTokenValiditySeconds(null);
} else {
client.setRefreshTokenValiditySeconds(rtSecs);
}

client.setAllowIntrospection(true);

if (isNull(client.getContacts())) {
client.setContacts(new HashSet<>());
}

if (isNull(client.getClientId())) {
client.setClientId(UUID.randomUUID().toString());
}

if (AUTH_METHODS_REQUIRING_SECRET.contains(client.getTokenEndpointAuthMethod())) {
client.setClientSecret(generateClientSecret());
}

client.setAuthorities(Sets.newHashSet(Authorities.ROLE_CLIENT));

return client;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml2.metadata.IDPSSODescriptor;
import org.opensaml.saml2.metadata.LocalizedString;
import org.opensaml.saml2.metadata.provider.MetadataProvider;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.opensaml.saml2.metadata.provider.ObservableMetadataProvider;
Expand All @@ -49,7 +51,8 @@

@Component
@Profile("saml")
public class DefaultMetadataLookupService implements MetadataLookupService, ObservableMetadataProvider.Observer {
public class DefaultMetadataLookupService
implements MetadataLookupService, ObservableMetadataProvider.Observer {

private static final int MAX_RESULTS = 20;
private static final Logger LOG = LoggerFactory.getLogger(DefaultMetadataLookupService.class);
Expand All @@ -70,7 +73,7 @@ private void initializeMetadataSet() throws MetadataProviderException {

final Instant startTime = Instant.now();
LOG.debug("Initializing IdP descriptor list from metadata");

Set<IdpDescription> newDescriptions = new HashSet<>();

for (String idpName : metadataManager.getIDPEntityNames()) {
Expand Down Expand Up @@ -107,6 +110,8 @@ private IdpDescription descriptionFromMetadata(EntityDescriptor descriptor) {

if (!uiInfo.getDisplayNames().isEmpty()) {
result.setOrganizationName(uiInfo.getDisplayNames().get(0).getName().getLocalString());
result
.setDisplayNames(uiInfo.getDisplayNames().stream().map(dn -> dn.getName()).toList());
}
}
}
Expand Down Expand Up @@ -140,6 +145,17 @@ private Optional<List<IdpDescription>> lookupByEntityId(String text) {
public List<IdpDescription> lookupIdp(String text) {

List<IdpDescription> result = new ArrayList<>();
String textToFind = text.toLowerCase();

Predicate<IdpDescription> filterForDescriptions = description -> {
if (description.getDisplayNames() != null) {
return description.getDisplayNames()
.stream()
.anyMatch(name -> name.getLocalString().toLowerCase().contains(textToFind));
} else {
return description.getEntityId().toLowerCase().contains(textToFind);
}
};

lookupByEntityId(text).ifPresent(result::addAll);

Expand All @@ -149,9 +165,24 @@ public List<IdpDescription> lookupIdp(String text) {

try {
lock.readLock().lock();

return descriptions.stream()
.filter(p -> p.getOrganizationName().toLowerCase().contains(text.toLowerCase()))
.filter(filterForDescriptions)
.limit(MAX_RESULTS)
.map(description -> {
List<LocalizedString> displayNames = description.getDisplayNames();
if (displayNames != null) {

for (LocalizedString displayName : displayNames) {
String localString = displayName.getLocalString();
if (localString.toLowerCase().contains(textToFind)) {
description.setOrganizationName(localString);
break;
}
}
}
return description;
})
.collect(Collectors.toList());
} finally {
lock.readLock().unlock();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,20 @@
*/
package it.infn.mw.iam.authn.saml.model;

import java.util.List;

import org.opensaml.saml2.metadata.LocalizedString;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;

@JsonInclude(Include.NON_EMPTY)
public class IdpDescription {
public class IdpDescription {

private String entityId;
private String organizationName;
private String imageUrl;
private List<LocalizedString> displayNames;

public String getEntityId() {
return entityId;
Expand All @@ -49,9 +54,18 @@ public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}

public List<LocalizedString> getDisplayNames() {
return displayNames;
}

public void setDisplayNames(List<LocalizedString> displayNames) {
this.displayNames = displayNames;
}

@Override
public String toString() {
return "IdpDescription [entityId=" + entityId + ", organizationName=" + organizationName
+ ", imageUrl=" + imageUrl + "]";
+ ", imageUrl=" + imageUrl + ", displayNames=" + displayNames + "]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@

import static it.infn.mw.iam.core.oauth.profile.ScopeAwareProfileResolver.AARC_PROFILE_ID;
import static it.infn.mw.iam.core.oauth.profile.ScopeAwareProfileResolver.IAM_PROFILE_ID;
import static it.infn.mw.iam.core.oauth.profile.ScopeAwareProfileResolver.KC_PROFILE_ID;
import static it.infn.mw.iam.core.oauth.profile.ScopeAwareProfileResolver.WLCG_PROFILE_ID;

import java.time.Clock;
import java.util.Arrays;
import java.util.Map;

import org.h2.server.web.WebServlet;
import org.mitre.oauth2.repository.SystemScopeRepository;
import org.mitre.oauth2.service.IntrospectionResultAssembler;
import org.mitre.oauth2.service.impl.DefaultIntrospectionResultAssembler;
import org.mitre.oauth2.service.impl.DefaultOAuth2AuthorizationCodeService;
Expand Down Expand Up @@ -69,6 +71,12 @@
import it.infn.mw.iam.core.oauth.profile.iam.IamJWTProfileIdTokenCustomizer;
import it.infn.mw.iam.core.oauth.profile.iam.IamJWTProfileTokenIntrospectionHelper;
import it.infn.mw.iam.core.oauth.profile.iam.IamJWTProfileUserinfoHelper;
import it.infn.mw.iam.core.oauth.profile.keycloak.KeycloakGroupHelper;
import it.infn.mw.iam.core.oauth.profile.keycloak.KeycloakIdTokenCustomizer;
import it.infn.mw.iam.core.oauth.profile.keycloak.KeycloakIntrospectionHelper;
import it.infn.mw.iam.core.oauth.profile.keycloak.KeycloakJWTProfile;
import it.infn.mw.iam.core.oauth.profile.keycloak.KeycloakProfileAccessTokenBuilder;
import it.infn.mw.iam.core.oauth.profile.keycloak.KeycloakUserinfoHelper;
import it.infn.mw.iam.core.oauth.profile.wlcg.WLCGGroupHelper;
import it.infn.mw.iam.core.oauth.profile.wlcg.WLCGJWTProfile;
import it.infn.mw.iam.core.oauth.scope.matchers.DefaultScopeMatcherRegistry;
Expand Down Expand Up @@ -152,6 +160,27 @@ JWTProfile aarcJwtProfile(IamProperties props, IamAccountRepository accountRepo,
return new AarcJWTProfile(atBuilder, idHelper, uiHelper, intrHelper);
}

@Bean(name = "kcJwtProfile")
JWTProfile kcJwtProfile(IamProperties props, IamAccountRepository accountRepo,
ScopeClaimTranslationService converter, UserInfoService userInfoService, ScopeMatcherRegistry registry, ClaimValueHelper claimHelper) {

KeycloakGroupHelper groupHelper = new KeycloakGroupHelper();

KeycloakProfileAccessTokenBuilder atBuilder =
new KeycloakProfileAccessTokenBuilder(props, groupHelper);

KeycloakUserinfoHelper uiHelper =
new KeycloakUserinfoHelper(props, userInfoService);

KeycloakIdTokenCustomizer idHelper =
new KeycloakIdTokenCustomizer(accountRepo, converter, claimHelper, groupHelper, props);

BaseIntrospectionHelper intrHelper = new KeycloakIntrospectionHelper(props,
new DefaultIntrospectionResultAssembler(), registry, groupHelper);

return new KeycloakJWTProfile(atBuilder, idHelper, uiHelper, intrHelper);
}

@Bean(name = "iamJwtProfile")
JWTProfile iamJwtProfile(IamProperties props, IamAccountRepository accountRepo,
ScopeClaimTranslationService converter, ClaimValueHelper claimHelper,
Expand Down Expand Up @@ -188,7 +217,9 @@ attributeMapHelper, new DefaultIntrospectionResultAssembler(), registry,
@Bean
JWTProfileResolver jwtProfileResolver(@Qualifier("iamJwtProfile") JWTProfile iamProfile,
@Qualifier("wlcgJwtProfile") JWTProfile wlcgProfile,
@Qualifier("aarcJwtProfile") JWTProfile aarcProfile, IamProperties properties,
@Qualifier("aarcJwtProfile") JWTProfile aarcProfile,
@Qualifier("kcJwtProfile") JWTProfile kcProfile,
IamProperties properties,
ClientDetailsService clientDetailsService) {

JWTProfile defaultProfile = iamProfile;
Expand All @@ -203,10 +234,16 @@ JWTProfileResolver jwtProfileResolver(@Qualifier("iamJwtProfile") JWTProfile iam
defaultProfile = aarcProfile;
}

if (it.infn.mw.iam.config.IamProperties.JWTProfile.Profile.KC
.equals(properties.getJwtProfile().getDefaultProfile())) {
defaultProfile = kcProfile;
}

Map<String, JWTProfile> profileMap = Maps.newHashMap();
profileMap.put(IAM_PROFILE_ID, iamProfile);
profileMap.put(WLCG_PROFILE_ID, wlcgProfile);
profileMap.put(AARC_PROFILE_ID, aarcProfile);
profileMap.put(KC_PROFILE_ID, kcProfile);

LOG.info("Default JWT profile: {}", defaultProfile.name());
return new ScopeAwareProfileResolver(defaultProfile, profileMap, clientDetailsService);
Expand Down Expand Up @@ -252,9 +289,9 @@ FilterRegistrationBean<EnforceAupFilter> aupSignatureCheckFilter(AUPSignatureChe


@Bean
ScopeMatcherRegistry customScopeMatchersRegistry(ScopeMatchersProperties properties) {
ScopeMatcherRegistry customScopeMatchersRegistry(ScopeMatchersProperties properties, SystemScopeRepository scopeRepo) {
ScopeMatchersPropertiesParser parser = new ScopeMatchersPropertiesParser();
return new DefaultScopeMatcherRegistry(parser.parseScopeMatchersProperties(properties));
return new DefaultScopeMatcherRegistry(parser.parseScopeMatchersProperties(properties), scopeRepo);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ public static class JWTProfile {
public enum Profile {
IAM,
WLCG,
AARC
AARC,
KC
}

Profile defaultProfile = Profile.IAM;
Expand Down
Loading

0 comments on commit 59b0b05

Please sign in to comment.