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

INDIGO IAM v1.10.3 release #899

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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 iam-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>it.infn.mw.iam-parent</groupId>
<artifactId>iam-parent</artifactId>
<version>1.10.2</version>
<version>1.10.3</version>
</parent>

<groupId>it.infn.mw.iam-common</groupId>
Expand Down
2 changes: 1 addition & 1 deletion iam-login-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<groupId>it.infn.mw.iam-parent</groupId>
<artifactId>iam-parent</artifactId>
<version>1.10.2</version>
<version>1.10.3</version>
</parent>

<groupId>it.infn.mw.iam-login-service</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
Expand All @@ -35,7 +34,6 @@
public class AccountUtils {
IamAccountRepository accountRepo;

@Autowired
public AccountUtils(IamAccountRepository accountRepo) {
this.accountRepo = accountRepo;
}
Expand Down Expand Up @@ -73,8 +71,7 @@ public Optional<IamAccount> getAuthenticatedUserAccount(Authentication authn) {

Authentication userAuthn = authn;

if (authn instanceof OAuth2Authentication) {
OAuth2Authentication oauth = (OAuth2Authentication) authn;
if (authn instanceof OAuth2Authentication oauth) {
if (oauth.getUserAuthentication() == null) {
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,19 @@
import static it.infn.mw.iam.api.utils.ValidationErrorUtils.stringifyValidationError;
import static java.lang.String.format;
import static org.springframework.http.HttpStatus.NO_CONTENT;
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -57,7 +54,6 @@ public class AccountAttributesController {
final IamAccountService accountService;
final AttributeDTOConverter converter;

@Autowired
public AccountAttributesController(IamAccountService accountService,
AttributeDTOConverter converter) {
this.converter = converter;
Expand All @@ -71,7 +67,7 @@ private void handleValidationError(BindingResult result) {
}
}

@RequestMapping(value = "/iam/account/{id}/attributes", method = RequestMethod.GET)
@GetMapping(value = "/iam/account/{id}/attributes")
@PreAuthorize("#iam.hasScope('iam:admin.read') or #iam.isUser(#id) or #iam.hasAnyDashboardRole('ROLE_ADMIN', 'ROLE_GM')")
public List<AttributeDTO> getAttributes(@PathVariable String id) {

Expand All @@ -84,7 +80,7 @@ public List<AttributeDTO> getAttributes(@PathVariable String id) {
return results;
}

@RequestMapping(value = "/iam/account/{id}/attributes", method = PUT)
@PutMapping(value = "/iam/account/{id}/attributes")
@PreAuthorize("#iam.hasScope('iam:admin.write') or #iam.hasDashboardRole('ROLE_ADMIN')")
public void setAttribute(@PathVariable String id, @RequestBody @Validated AttributeDTO attribute,
final BindingResult validationResult) {
Expand All @@ -98,7 +94,7 @@ public void setAttribute(@PathVariable String id, @RequestBody @Validated Attrib
accountService.setAttribute(account, attr);
}

@RequestMapping(value = "/iam/account/{id}/attributes", method = DELETE)
@DeleteMapping(value = "/iam/account/{id}/attributes")
@PreAuthorize("#iam.hasScope('iam:admin.write') or #iam.hasDashboardRole('ROLE_ADMIN')")
@ResponseStatus(value = NO_CONTENT)
public void deleteAttribute(@PathVariable String id, @Validated AttributeDTO attribute,
Expand All @@ -114,14 +110,12 @@ public void deleteAttribute(@PathVariable String id, @Validated AttributeDTO att

@ResponseStatus(code = HttpStatus.BAD_REQUEST)
@ExceptionHandler(InvalidAttributeError.class)
@ResponseBody
public ErrorDTO handleValidationError(InvalidAttributeError e) {
return ErrorDTO.fromString(e.getMessage());
}

@ResponseStatus(code = HttpStatus.NOT_FOUND)
@ExceptionHandler(NoSuchAccountError.class)
@ResponseBody
public ErrorDTO handleNoSuchAccountError(NoSuchAccountError e) {
return ErrorDTO.fromString(e.getMessage());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,16 @@
package it.infn.mw.iam.api.account.group_manager;

import java.util.List;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -50,7 +49,6 @@ public class AccountGroupManagerController {
final IamGroupRepository groupRepository;
final UserConverter userConverter;

@Autowired
public AccountGroupManagerController(AccountGroupManagerService service,
IamAccountRepository accountRepo, IamGroupRepository groupRepository,
UserConverter userConverter) {
Expand All @@ -60,9 +58,7 @@ public AccountGroupManagerController(AccountGroupManagerService service,
this.userConverter = userConverter;
}



@RequestMapping(value = "/iam/account/{accountId}/managed-groups", method = RequestMethod.GET)
@GetMapping(value = "/iam/account/{accountId}/managed-groups")
@PreAuthorize("#iam.hasScope('iam:admin.read') or #iam.hasDashboardRole('ROLE_ADMIN') or #iam.isUser(#accountId)")
public AccountManagedGroupsDTO getAccountManagedGroupsInformation(
@PathVariable String accountId) {
Expand All @@ -72,8 +68,7 @@ public AccountManagedGroupsDTO getAccountManagedGroupsInformation(
return service.getManagedGroupInfoForAccount(account);
}

@RequestMapping(value = "/iam/account/{accountId}/managed-groups/{groupId}",
method = RequestMethod.POST)
@PostMapping(value = "/iam/account/{accountId}/managed-groups/{groupId}")
@PreAuthorize("#iam.hasScope('iam:admin.write') or #iam.hasDashboardRole('ROLE_ADMIN')")
@ResponseStatus(value = HttpStatus.CREATED)
public void addManagedGroupToAccount(@PathVariable String accountId,
Expand All @@ -88,8 +83,7 @@ public void addManagedGroupToAccount(@PathVariable String accountId,
service.addManagedGroupForAccount(account, group);
}

@RequestMapping(value = "/iam/account/{accountId}/managed-groups/{groupId}",
method = RequestMethod.DELETE)
@DeleteMapping(value = "/iam/account/{accountId}/managed-groups/{groupId}")
@PreAuthorize("#iam.hasScope('iam:admin.write') or #iam.hasDashboardRole('ROLE_ADMIN')")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void removeManagedGroupFromAccount(@PathVariable String accountId,
Expand All @@ -104,7 +98,7 @@ public void removeManagedGroupFromAccount(@PathVariable String accountId,
service.removeManagedGroupForAccount(account, group);
}

@RequestMapping(value = "/iam/group/{groupId}/group-managers", method=RequestMethod.GET)
@GetMapping(value = "/iam/group/{groupId}/group-managers")
@PreAuthorize("#iam.hasScope('iam:admin.read') or #iam.hasDashboardRole('ROLE_ADMIN') or #iam.isGroupManager(#groupId)")
public List<ScimUser> getGroupManagersForGroup(@PathVariable String groupId) {
IamGroup group = groupRepository.findByUuid(groupId)
Expand All @@ -113,7 +107,7 @@ public List<ScimUser> getGroupManagersForGroup(@PathVariable String groupId) {
return service.getGroupManagersForGroup(group)
.stream()
.map(userConverter::dtoFromEntity)
.collect(Collectors.toList());
.toList();

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
Expand All @@ -54,14 +55,13 @@ public class AccountLinkingController extends ExternalAuthenticationHandlerSuppo
@Value("${iam.account-linking.enable}")
private Boolean accountLinkingEnabled;

@Autowired
public AccountLinkingController(AccountLinkingService s) {
linkingService = s;
}


@PreAuthorize("hasRole('USER')")
@RequestMapping(value = "/X509", method = RequestMethod.DELETE)
@DeleteMapping(value = "/X509")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void unlinkX509Certificate(Principal principal, @RequestParam String certificateSubject,
RedirectAttributes attributes) {
Expand All @@ -72,7 +72,7 @@ public void unlinkX509Certificate(Principal principal, @RequestParam String cert


@PreAuthorize("hasRole('USER')")
@RequestMapping(value = "/X509", method = RequestMethod.POST)
@PostMapping(value = "/X509")
public String linkX509Certificate(HttpSession session, Principal principal,
RedirectAttributes attributes) {

Expand Down Expand Up @@ -104,7 +104,7 @@ private void checkAccountLinkingEnabled(RedirectAttributes attributes) {
}

@PreAuthorize("hasRole('USER')")
@RequestMapping(value = "/{type}", method = RequestMethod.POST)
@PostMapping(value = "/{type}")
public void linkAccount(@PathVariable ExternalAuthenticationType type,
@RequestParam(value = "id", required = false) String externalIdpId, Authentication authn,
final RedirectAttributes redirectAttributes, HttpServletRequest request,
Expand Down Expand Up @@ -163,7 +163,7 @@ public String finalizeAccountLinking(@PathVariable ExternalAuthenticationType ty
}

@PreAuthorize("hasRole('USER')")
@RequestMapping(value = "/{type}", method = RequestMethod.DELETE)
@DeleteMapping(value = "/{type}")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void unlinkAccount(@PathVariable ExternalAuthenticationType type, Principal principal,
@RequestParam("iss") String issuer, @RequestParam("sub") String subject,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,16 @@
import java.util.Date;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import it.infn.mw.iam.audit.events.account.AccountLinkedEvent;
import it.infn.mw.iam.audit.events.account.AccountUnlinkedEvent;
import it.infn.mw.iam.audit.events.account.X509CertificateLinkedEvent;
import it.infn.mw.iam.audit.events.account.X509CertificateUnlinkedEvent;
import it.infn.mw.iam.audit.events.account.X509CertificateUpdatedEvent;
import it.infn.mw.iam.audit.events.account.x509.X509CertificateLinkedEvent;
import it.infn.mw.iam.audit.events.account.x509.X509CertificateUnlinkedEvent;
import it.infn.mw.iam.authn.AbstractExternalAuthenticationToken;
import it.infn.mw.iam.authn.ExternalAccountLinker;
import it.infn.mw.iam.authn.ExternalAuthenticationRegistrationInfo.ExternalAuthenticationType;
Expand All @@ -44,18 +43,21 @@
import it.infn.mw.iam.persistence.model.IamX509Certificate;
import it.infn.mw.iam.persistence.model.IamX509ProxyCertificate;
import it.infn.mw.iam.persistence.repository.IamAccountRepository;
import it.infn.mw.iam.persistence.repository.IamX509CertificateRepository;

@Service
public class DefaultAccountLinkingService
implements AccountLinkingService, ApplicationEventPublisherAware {

final IamAccountRepository iamAccountRepository;
final IamX509CertificateRepository certificateRepository;
final ExternalAccountLinker externalAccountLinker;
private ApplicationEventPublisher eventPublisher;

@Autowired
public DefaultAccountLinkingService(IamAccountRepository repo, ExternalAccountLinker linker) {
public DefaultAccountLinkingService(IamAccountRepository repo,
IamX509CertificateRepository certificateRepository, ExternalAccountLinker linker) {
this.iamAccountRepository = repo;
this.certificateRepository = certificateRepository;
this.externalAccountLinker = linker;
}

Expand Down Expand Up @@ -140,56 +142,50 @@ public void linkX509Certificate(Principal authenticatedUser,

IamAccount userAccount = findAccount(authenticatedUser);

iamAccountRepository.findByCertificateSubject(x509Credential.getSubject())
.ifPresent(linkedAccount -> {
if (!linkedAccount.getUuid().equals(userAccount.getUuid())) {
throw new AccountAlreadyLinkedError(
format("X.509 credential with subject '%s' is already linked to another user",
x509Credential.getSubject()));
}
});
Optional<IamAccount> linkedAccount =
certificateRepository.findBySubjectDn(x509Credential.getSubject()).stream().findFirst();

Optional<IamX509Certificate> linkedCert = userAccount.getX509Certificates()
.stream()
.filter(c -> c.getSubjectDn().equals(x509Credential.getSubject()) && c.getIssuerDn().equals(x509Credential.getIssuer()))
.findAny();
// check if the x509Credential is linked to another user
if (linkedAccount.isPresent() && !linkedAccount.get().getUuid().equals(userAccount.getUuid())) {
throw new AccountAlreadyLinkedError(
format("X.509 credential with subject '%s' is already linked to another user",
x509Credential.getSubject()));
}

if (linkedCert.isPresent()) {
Optional<IamX509Certificate> linkedCertificate = certificateRepository
.findBySubjectDnAndIssuerDn(x509Credential.getSubject(), x509Credential.getIssuer());

linkedCert.ifPresent(c -> {
c.setCertificate(x509Credential.getCertificateChainPemString());
c.setLastUpdateTime(new Date());
});
if (linkedCertificate.isPresent()) {

linkedCertificate.get().setCertificate(x509Credential.getCertificateChainPemString());
linkedCertificate.get().setLastUpdateTime(new Date());
certificateRepository.save(linkedCertificate.get());
userAccount.getX509Certificates().remove(linkedCertificate.get());
userAccount.getX509Certificates().add(linkedCertificate.get());
userAccount.touch();
iamAccountRepository.save(userAccount);

eventPublisher.publishEvent(new X509CertificateUpdatedEvent(this, userAccount,
String.format("User '%s' has updated its linked certificate with subject '%s'",
userAccount.getUsername(), x509Credential.getSubject()),
x509Credential));

} else {

Date now = new Date();
IamX509Certificate newCert = x509Credential.asIamX509Certificate();
newCert.setLabel(String.format("cert-%d", userAccount.getX509Certificates().size()));

newCert.setCreationTime(now);
newCert.setLastUpdateTime(now);

newCert.setPrimary(true);
newCert.setAccount(userAccount);
certificateRepository.save(newCert);
userAccount.getX509Certificates().add(newCert);
userAccount.touch();

iamAccountRepository.save(userAccount);

eventPublisher.publishEvent(new X509CertificateLinkedEvent(this, userAccount,
String.format("User '%s' linked certificate with subject '%s' to his/her membership",
userAccount.getUsername(), x509Credential.getSubject()),
x509Credential));

}
}

Expand Down
Loading
Loading