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.11.0 release #900

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
22faeb3
Bump version to 1.11.0
enricovianello Oct 16, 2024
ae09f39
Self-service upload of user certificate (#750)
darcato Oct 16, 2024
3fdc770
Bump version to 1.10.3
rmiccoli Nov 18, 2024
99fc6fa
Handle HEAD requests
rmiccoli Nov 13, 2024
f15ef57
Update matchingPolicy
garaimanoj Oct 22, 2024
5acde91
Redirect to login page when signing AUP
federicaagostini Nov 14, 2024
e2588ce
Bump mitreid version to 1.3.7.cnaf-20241119
rmiccoli Nov 19, 2024
d93535f
Fix tests
rmiccoli Nov 19, 2024
af34308
Add confirmation before rotate client secret
SteDev2 Nov 20, 2024
6bbaccd
Grant admin scopes to admin-approved clients only
rmiccoli Jul 18, 2024
4026957
Fix account mapping
rmiccoli Nov 22, 2024
f628b97
Add POST endpoint for registration requests confirmation (#881)
enricovianello Nov 22, 2024
8836869
Fix CERN lifecycle handler (#871)
enricovianello Nov 22, 2024
aecb995
Revert "Self-service upload of user certificate (#750)"
enricovianello Nov 26, 2024
2777efe
Revert "Bump version to 1.11.0"
enricovianello Nov 26, 2024
9955809
Cosmetic fixes before 1.10.3 release (#882)
enricovianello Nov 26, 2024
6018c3e
Merge branch 'v1.10.3' into develop
enricovianello Nov 26, 2024
1e75841
Bump version to 1.11.0
enricovianello Nov 26, 2024
023f7d0
Exclude IAM optional groups from VOMS AC (#894)
rmiccoli Dec 16, 2024
118b57e
Fix CERN lifecycle logic (#896)
enricovianello Dec 17, 2024
35240c2
Find account by certificate sub and iss in VOMS AA (#897)
rmiccoli Dec 17, 2024
3a51b67
Avoid NullPointerException
enricovianello Dec 18, 2024
f0d2e11
Fix code smells
rmiccoli Dec 19, 2024
f015882
Remove Institute label
enricovianello Dec 19, 2024
40db2f3
Log lifecycle handlers start and end with INFO level
enricovianello Dec 19, 2024
ac90533
Delete rogue registration requests without sending a reason (#858)
garaimanoj Dec 19, 2024
7d59c22
Prevent the issue of broken SAML login flow
enricovianello Nov 27, 2024
2f900ff
Add MFA support for local credentials (#733)
rmiccoli Dec 19, 2024
1348b1c
Add 1.11.0 to CHANGELOG
enricovianello Dec 19, 2024
e11b018
Remove transient keywords to avoid missing info stored in session
enricovianello Dec 20, 2024
dc9e772
Fix infinite recursion on object serialization
enricovianello Dec 20, 2024
e9786f2
Fix AuthZ on endpoints that requires identity
enricovianello Dec 20, 2024
10ae37e
Fix lifecycle management
enricovianello Dec 20, 2024
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
1 change: 1 addition & 0 deletions .github/workflows/sonar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- develop

pull_request:
types: [opened, edited, reopened, synchronize]

Expand Down
45 changes: 42 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,52 @@
# Changelog

## 1.11.0 (2024-12-19)

### What's Changed

* Add confirmation before rotate client secret by @SteDev2 in https://github.com/indigo-iam/iam/pull/875
* Fix account mapping in VOMS AA by @rmiccoli in https://github.com/indigo-iam/iam/pull/872
* Add POST endpoint for registration requests confirmation by @enricovianello in https://github.com/indigo-iam/iam/pull/881
* Fix CERN lifecycle handler by @enricovianello in https://github.com/indigo-iam/iam/pull/871, https://github.com/indigo-iam/iam/pull/896
* Grant admin scopes to admin-approved clients only by @rmiccoli in https://github.com/indigo-iam/iam/commit/6bbaccd4e85cc1dc1659ea10fa31dd5307b2dc62
* Client-credentials flow won't create a refresh token by @rmiccoli in https://github.com/indigo-iam/OpenID-Connect-Java-Spring-Server/pull/22
* Redirect to login page when signing AUP by @federicaagostini in https://github.com/indigo-iam/iam/commit/5acde91cd333d139991e2ba1ee6d5fe062d986a0
* Fix missing update of matchingPolicy by @garaimanoj in https://github.com/indigo-iam/iam/commit/f15ef57b1e11f3f08e1b5cb2462520efd3c1108d
* Find account by certificate sub and iss in VOMS AA by @rmiccoli in https://github.com/indigo-iam/iam/pull/897
* Exclude IAM optional groups from VOMS AC by @rmiccoli in https://github.com/indigo-iam/iam/pull/894
* Find account by certificate sub and iss in VOMS AA by @rmiccoli in https://github.com/indigo-iam/iam/pull/897
* Prevent the issue of broken SAML login flow by @DonaldChung-HK in https://github.com/indigo-iam/iam/pull/885

### Added

* (_Experimental_*) Implement MFA by @sam-glendenning, @rmiccoli, @garaimanoj, @Sae126V in https://github.com/indigo-iam/iam/pull/733

(*) This initial release featuring Multi-Factor Authentication is experimental and will be enhanced and expanded with new features in future releases, based also on user feedback.

### MFA experimental feature summary

* Each authenticated user can enable/disable MFA through a button in their homepage
* user will use an authenticator, as it is required to generate the time-based one-time passwords (TOTPs) necessary for authentication
* If issues arise with the authenticator, the IAM administrator can disable MFA for a user
* Authenticator working for local authentication only
* integration with X.509 certificates and external providers not yet supported
* Encryption and decryption of MFA secrets

#### Configuration

The `mfa` Spring profile is used to enable MFA functionality. By default, MFA is disabled for all users.

## 1.10.2 (2024-09-30)

## What's Changed
### What's Changed

* Add devcontainer configuration https://github.com/indigo-iam/iam/pull/835
* Track refresh tokens in access token AUDIT logs https://github.com/indigo-iam/iam/pull/838
* Combine CERN HR logic with internal life-cycle https://github.com/indigo-iam/iam/pull/844

## 1.10.1 (2024-08-22)

## What's Fixed
### What's Fixed

* Fix repeated suspensions https://github.com/indigo-iam/iam/pull/831
* Fix typo in AUDIT log for suspended accounts https://github.com/indigo-iam/iam/pull/832
Expand Down Expand Up @@ -259,7 +295,6 @@ fixes several bugs for the IAM login service.
## 1.7.2 (2021-12-03)

This release provides a single dependency change for the IAM login service
application.

### Added

Expand All @@ -271,6 +306,10 @@ This release provides changes and bug fixes to the IAM test client application.

### Added

This release provides changes and bug fixes to the IAM test client application.

### Added

- The IAM test client application, in its default configuration, no longer
exposes tokens, but only the claims contained in tokens. It's possible to
revert to the previous behavior by setting the `IAM_CLIENT_HIDE_TOKENS=false`
Expand Down
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pipeline {
post {
always {
script {
maybeArchiveJUnitReports()
maybeArchiveJUnitReportsWithJacoco()
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions compose/custom-nginx/iam.conf
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ server {
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
proxy_set_header X-SSL-Protocol $ssl_protocol;
proxy_set_header X-SSL-Server-Name $ssl_server_name;

proxy_cookie_flags ~ secure samesite=none;
}

location /iam-test-client {
Expand Down
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.11.0</version>
</parent>

<groupId>it.infn.mw.iam-common</groupId>
Expand Down
1 change: 1 addition & 0 deletions iam-login-service/docker/Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM eclipse-temurin:17 as builder

RUN mkdir /indigo-iam
WORKDIR /indigo-iam
COPY iam-login-service.war /indigo-iam/
Expand Down
15 changes: 13 additions & 2 deletions 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.11.0</version>
</parent>

<groupId>it.infn.mw.iam-login-service</groupId>
Expand Down Expand Up @@ -92,7 +92,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>


<!-- Web Jars -->
<dependency>
Expand Down Expand Up @@ -221,6 +220,11 @@
<artifactId>spring-security-oauth2</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
Expand Down Expand Up @@ -406,6 +410,13 @@
<artifactId>jaxb-runtime</artifactId>
</dependency>

<!-- Secret, TOTP, QR code generator for multi-factor authentication -->
<dependency>
<groupId>dev.samstevens.totp</groupId>
<artifactId>totp</artifactId>
<version>1.7.1</version>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,16 @@
*/
package it.infn.mw.iam.api.account;

import static java.util.Objects.isNull;

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;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Component;

import it.infn.mw.iam.authn.util.Authorities;
import it.infn.mw.iam.core.ExtendedAuthenticationToken;
import it.infn.mw.iam.persistence.model.IamAccount;
import it.infn.mw.iam.persistence.repository.IamAccountRepository;

Expand All @@ -35,35 +33,43 @@
public class AccountUtils {
IamAccountRepository accountRepo;

@Autowired
public AccountUtils(IamAccountRepository accountRepo) {
this.accountRepo = accountRepo;
}

public boolean isRegisteredUser(Authentication auth) {
if (auth == null || auth.getAuthorities() == null) {
if (auth == null || auth.getAuthorities().isEmpty()) {
return false;
}

return auth.getAuthorities().contains(Authorities.ROLE_USER);
}

public boolean isAdmin(Authentication auth) {
if (auth == null || auth.getAuthorities() == null) {
if (auth == null || auth.getAuthorities().isEmpty()) {
return false;
}

return auth.getAuthorities().contains(Authorities.ROLE_ADMIN);
}

public boolean isPreAuthenticated(Authentication auth) {
if (auth == null || auth.getAuthorities().isEmpty()) {
return false;
}

return auth.getAuthorities().contains(Authorities.ROLE_PRE_AUTHENTICATED);
}

public boolean isAuthenticated() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();

return isAuthenticated(auth);
}

public boolean isAuthenticated(Authentication auth) {
return !(isNull(auth) || auth instanceof AnonymousAuthenticationToken);
return auth != null && !(auth instanceof AnonymousAuthenticationToken)
&& (!(auth instanceof ExtendedAuthenticationToken) || auth.isAuthenticated());
}

public Optional<IamAccount> getAuthenticatedUserAccount(Authentication authn) {
Expand All @@ -72,7 +78,7 @@ public Optional<IamAccount> getAuthenticatedUserAccount(Authentication authn) {
}

Authentication userAuthn = authn;

if (authn instanceof OAuth2Authentication) {
OAuth2Authentication oauth = (OAuth2Authentication) authn;
if (oauth.getUserAuthentication() == null) {
Expand All @@ -86,13 +92,13 @@ public Optional<IamAccount> getAuthenticatedUserAccount(Authentication authn) {
}

public Optional<IamAccount> getAuthenticatedUserAccount() {

Authentication auth = SecurityContextHolder.getContext().getAuthentication();

return getAuthenticatedUserAccount(auth);
}
public Optional<IamAccount> getByAccountId(String accountId){

public Optional<IamAccount> getByAccountId(String accountId) {
return accountRepo.findByUuid(accountId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,19 @@
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.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 +56,6 @@ public class AccountAttributesController {
final IamAccountService accountService;
final AttributeDTOConverter converter;

@Autowired
public AccountAttributesController(IamAccountService accountService,
AttributeDTOConverter converter) {
this.converter = converter;
Expand All @@ -71,7 +69,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 +82,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 Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@

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 +50,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 +59,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 +69,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 +84,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 +99,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 Down
Loading
Loading