Skip to content
Open
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 @@ -17,28 +17,45 @@

import static org.apache.commons.lang3.StringUtils.isNotBlank;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

import it.infn.mw.iam.api.common.OffsetPageable;
import it.infn.mw.iam.api.scim.model.ScimAarcGroup;
import it.infn.mw.iam.api.scim.model.ScimGroup;
import it.infn.mw.iam.api.scim.model.ScimGroup.Builder;
import it.infn.mw.iam.api.scim.model.ScimGroupRef;
import it.infn.mw.iam.api.scim.model.ScimIndigoGroup;
import it.infn.mw.iam.api.scim.model.ScimLabel;
import it.infn.mw.iam.api.scim.model.ScimMemberRef;
import it.infn.mw.iam.api.scim.model.ScimMeta;
import it.infn.mw.iam.config.scim.ScimProperties;
import it.infn.mw.iam.core.user.IamAccountService;
import it.infn.mw.iam.persistence.model.IamAccount;
import it.infn.mw.iam.persistence.model.IamGroup;
import it.infn.mw.iam.persistence.model.IamLabel;
import it.infn.mw.iam.persistence.repository.IamAccountRepository;

@Service
public class GroupConverter implements Converter<ScimGroup, IamGroup> {

private final ScimResourceLocationProvider resourceLocationProvider;
private final ScimProperties scimProperties;
private final IamAccountRepository accountRepo;
private final IamAccountService accountService;

public GroupConverter(ScimResourceLocationProvider rlp) {

public GroupConverter(ScimResourceLocationProvider rlp, ScimProperties scimProperties,
IamAccountRepository accountRepo, IamAccountService accountService) {
this.resourceLocationProvider = rlp;
this.scimProperties = scimProperties;
this.accountRepo = accountRepo;
this.accountService = accountService;
}

/**
Expand Down Expand Up @@ -103,11 +120,31 @@ public ScimGroup dtoFromEntity(IamGroup entity) {
scimIndigoGroup.labels(labels);
}

return ScimGroup.builder(entity.getName())
Builder builder = ScimGroup.builder(entity.getName())
.id(entity.getUuid())
.meta(meta)
.indigoGroup(scimIndigoGroup.build())
.build();
}
.indigoGroup(scimIndigoGroup.build());

builder.enableAarc(scimProperties.isEnableAarc());

if (scimProperties.isEnableAarc()) {
long totalUsers = accountRepo.count();
OffsetPageable pr = new OffsetPageable(0, (int) totalUsers);
Page<IamAccount> accounts = accountService.findGroupMembers(entity, pr);
Set<ScimMemberRef> members = new HashSet<>();

for (IamAccount a : accounts.getContent()) {
members.add(ScimMemberRef.builder()
.value(a.getUuid())
.display(a.getUserInfo().getName())
.ref(resourceLocationProvider.userLocation(a.getUuid()))
.build());
}

ScimAarcGroup aarcGroup = ScimAarcGroup.builder().members(members).build();
builder.aarcGroup(aarcGroup);
}

return builder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,26 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import java.util.HashSet;
import java.util.Set;

import org.springframework.stereotype.Service;

import it.infn.mw.iam.api.account.group_manager.AccountGroupManagerService;
import it.infn.mw.iam.api.scim.exception.ScimException;
import it.infn.mw.iam.api.scim.model.ScimAarcName;
import it.infn.mw.iam.api.scim.model.ScimAddress;
import it.infn.mw.iam.api.scim.model.ScimAffiliation;
import it.infn.mw.iam.api.scim.model.ScimAssurance;
import it.infn.mw.iam.api.scim.model.ScimAttribute;
import it.infn.mw.iam.api.scim.model.ScimEntitlement;
import it.infn.mw.iam.api.scim.model.ScimGroupRef;
import it.infn.mw.iam.api.scim.model.ScimLabel;
import it.infn.mw.iam.api.scim.model.ScimMeta;
import it.infn.mw.iam.api.scim.model.ScimName;
import it.infn.mw.iam.api.scim.model.ScimPhoto;
import it.infn.mw.iam.api.scim.model.ScimUser;
import it.infn.mw.iam.config.IamProperties;
import it.infn.mw.iam.config.scim.ScimProperties;
import it.infn.mw.iam.config.scim.ScimProperties.AttributeDescriptor;
import it.infn.mw.iam.config.scim.ScimProperties.LabelDescriptor;
Expand All @@ -46,6 +54,12 @@
@Service
public class UserConverter implements Converter<ScimUser, IamAccount> {

public static final String REFEDS_ASSURANCE_URI = "https://refeds.org/assurance";
public static final String REFEDS_ASSURANCE_IAP_LOW_URI = "https://refeds.org/assurance/IAP/low";

public static final Set<String> DEFAULT_LOA =
Set.of(REFEDS_ASSURANCE_URI, REFEDS_ASSURANCE_IAP_LOW_URI);

private final ScimResourceLocationProvider resourceLocationProvider;

private final AddressConverter addressConverter;
Expand All @@ -57,20 +71,23 @@ public class UserConverter implements Converter<ScimUser, IamAccount> {

private final AccountGroupManagerService groupManagerService;

private final ScimProperties properties;
private final ScimProperties scimProperties;
private final IamProperties iamProperties;

public UserConverter(ScimProperties properties, ScimResourceLocationProvider rlp,
public UserConverter(ScimProperties scimProperties, ScimResourceLocationProvider rlp,
AddressConverter ac, OidcIdConverter oidc, SshKeyConverter sshc, SamlIdConverter samlc,
X509CertificateConverter x509Iamcc, AccountGroupManagerService groupManagerService) {
X509CertificateConverter x509Iamcc, AccountGroupManagerService groupManagerService,
IamProperties iamProperties) {

this.resourceLocationProvider = rlp;
this.properties = properties;
this.scimProperties = scimProperties;
this.addressConverter = ac;
this.oidcIdConverter = oidc;
this.sshKeyConverter = sshc;
this.samlIdConverter = samlc;
this.x509CertificateIamConverter = x509Iamcc;
this.groupManagerService = groupManagerService;
this.iamProperties = iamProperties;
}

@Override
Expand Down Expand Up @@ -239,7 +256,7 @@ public ScimUser dtoFromEntity(IamAccount entity) {
builder.affiliation(entity.getAffiliation());
}

for (LabelDescriptor ld : properties.getIncludeLabels()) {
for (LabelDescriptor ld : scimProperties.getIncludeLabels()) {
entity.getLabelByPrefixAndName(ld.getPrefix(), ld.getName())
.ifPresent(el -> builder.addLabel(ScimLabel.builder()
.withPrefix(el.getPrefix())
Expand All @@ -248,15 +265,15 @@ public ScimUser dtoFromEntity(IamAccount entity) {
.build()));
}

for (AttributeDescriptor ad : properties.getIncludeAttributes()) {
for (AttributeDescriptor ad : scimProperties.getIncludeAttributes()) {
entity.getAttributeByName(ad.getName())
.ifPresent(attribute -> builder.addAttribute(ScimAttribute.builder()
.withName(attribute.getName())
.withVaule(attribute.getValue())
.build()));
}

if (properties.isIncludeManagedGroups()) {
if (scimProperties.isIncludeManagedGroups()) {
groupManagerService.getManagedGroupInfoForAccount(entity)
.getManagedGroups()
.forEach(mg -> builder.addManagedGroup(ScimGroupRef.builder()
Expand All @@ -266,10 +283,33 @@ public ScimUser dtoFromEntity(IamAccount entity) {
.build()));
}

if (properties.isIncludeAuthorities()) {
if (scimProperties.isIncludeAuthorities()) {
entity.getAuthorities().forEach(a -> builder.addAuthority(a.getAuthority()));
}

builder.enableAarc(scimProperties.isEnableAarc());

if (scimProperties.isEnableAarc()) {
builder.voPersonId(entity.getUuid() + "@" + iamProperties.getOrganisation().getName());
builder.organizationName(iamProperties.getOrganisation().getName());
builder.aarcDisplayName(entity.getUserInfo().getName());
builder.aarcName(new ScimAarcName(getScimName(entity)));
builder.addAarcEmail(entity.getUserInfo().getEmail());

if (entity.hasAffiliation()) {
builder.addVoPersonExternalAffiliation(new ScimAffiliation(
entity.getAffiliation() + "@" + iamProperties.getOrganisation().getName()));
} else {
builder.addVoPersonExternalAffiliation(
new ScimAffiliation("member" + "@" + iamProperties.getOrganisation().getName()));
}

DEFAULT_LOA.forEach(a -> builder.addAssurance(new ScimAssurance(a)));

resolveGroups(entity.getUserInfo())
.forEach(e -> builder.addEntitlements(new ScimEntitlement(e)));
}

return builder.build();
}

Expand Down Expand Up @@ -319,4 +359,29 @@ private ScimPhoto getScimPhoto(IamAccount entity) {

return ScimPhoto.builder().value(entity.getUserInfo().getPicture()).build();
}

public Set<String> resolveGroups(IamUserInfo userInfo) {

Set<String> encodedGroups = new HashSet<>();
userInfo.getGroups().forEach(g -> encodedGroups.add(encodeGroup(g)));
return encodedGroups;
}

private String encodeGroup(IamGroup group) {

var aarcConfig = iamProperties.getAarcProfile();

String urnNid = aarcConfig.getUrnNid();
String urnDelegatedNamespace = aarcConfig.getUrnDelegatedNamespace();
String encodedGroupName = group.getName().replace("/", ":");

String encodedSubnamespace = "";
String urnSubnamespaces = aarcConfig.getUrnSubnamespaces();
if (urnSubnamespaces != null && !urnSubnamespaces.isBlank()) {
encodedSubnamespace = ":" + String.join(":", urnSubnamespaces.trim().split("\\s+"));
}

return String.format("urn:%s:%s%s:group:%s", urnNid, urnDelegatedNamespace, encodedSubnamespace,
encodedGroupName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Copyright (c) Istituto Nazionale di Fisica Nucleare (INFN). 2016-2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package it.infn.mw.iam.api.scim.model;

import java.util.Collections;
import java.util.Set;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class ScimAarcGroup {

private final Set<ScimMemberRef> members;

@JsonCreator
private ScimAarcGroup(@JsonProperty("members") Set<ScimMemberRef> members) {
this.members = members != null ? members : Collections.emptySet();
}

private ScimAarcGroup(Builder b) {
this.members = b.members != null ? b.members : Collections.emptySet();
}

public Set<ScimMemberRef> getMembers() {
return members;
}

public static Builder builder() {
return new Builder();
}

public static class Builder {

private Set<ScimMemberRef> members = Collections.emptySet();

public Builder members(Set<ScimMemberRef> members) {
this.members = members;
return this;
}

public ScimAarcGroup build() {
return new ScimAarcGroup(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Copyright (c) Istituto Nazionale di Fisica Nucleare (INFN). 2016-2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package it.infn.mw.iam.api.scim.model;

public class ScimAarcName {
private final String givenName;
private final String familyName;

public ScimAarcName(ScimName name) {
this.givenName = name.getGivenName();
this.familyName = name.getFamilyName();
}

public String getGivenName() {
return givenName;
}

public String getFamilyName() {
return familyName;
}
}
Loading
Loading