Skip to content

Commit

Permalink
feat(jans-auth-server): specify minimum acr for clients #343 (#3083)
Browse files Browse the repository at this point in the history
* feat(jans-auth-server): specify minimum acr for clients #343

* feat(jans-auth-server): added minimum acr properties to dynamic registration #343

* doc(jans-auth-server): added docs and updated swagger with new minimum acr related properties #343
  • Loading branch information
yuriyz committed Nov 28, 2022
1 parent 7c077b9 commit b0034ec
Show file tree
Hide file tree
Showing 11 changed files with 469 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
tags:
- administration
- client
- configuration
---

# Client Configuration

## ACR client configuration

There are 4 client configuration properties related to ACR:

- `default_acr_values` - string array, default acr values which are set when `acr_values` is missed in authorization request.
- `minimumAcrLevel` - integer value which sets minimum acr level.
- `minimumAcrLevelAutoresolve` - boolean value, if `false` and `minimumAcrLevel` is higher then current `acr_values` then reject request. If `true` - resolve acr according to either client's `minimumAcrPriorityList` or AS `auth_level_mapping`
- `minimumAcrPriorityList` - string array, enables client to specify the acr order of preference, rather then just the next lowest integer value

AS process properties in following order:
1. if `acr_values` is absent, set `acr_values` from `default_acr_values`
2. Otherwise if present, checking minimum acr level:
- check `minimumAcrLevel`, if current acr level is higher or equals to `minimumAcrLevel` then proceed request processing without changes
- if `minimumAcrLevel` is less then current acr level and `minimumAcrLevelAutoresolve=false` -> reject request (return bad request error)
- if `minimumAcrLevel` is less then current acr level and `minimumAcrLevelAutoresolve=true` -> pickup value from `minimumAcrPriorityList` or if it's empty take nearest acr value that satisfy `minimumAcrLevel`

For example, given:
1. `minimumAcrLevel` = 14
1. `default_acr_values` = "basic"
1. `minimumAcrPriorityList` = ["u2f", "passkey", "usb_fido_key", "super_gluu"]
1. OP `auth_level_mapping` :
```
"auth_level_mapping": {
"1": ["basic"],
"5": ["otp"],
"10": ["u2f"],
"11": ["super_gluu"],
"20": ["passkey"],
"30": ["usb_fido_key"]
}
```

- if current `acr_values=u2f` and `minimumAcrLevelAutoresolve=false` -> request is rejected
- if current `acr_values=u2f` and `minimumAcrLevelAutoresolve=true` -> `acr_values` set to `acr_values=passkey` and request continue processing
- if current `acr_values=usb_fido_key` -> current acr is higher then minimum. Thus nothing to do.

If `minimumAcrPriorityList` is missing, then the AS can pick the next highest acr in the `auth_level_mapping`. In the example above, that would be `passkey`.
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ public class RegisterRequest extends BaseRequest {
private SignatureAlgorithm tokenEndpointAuthSigningAlg;
private Integer defaultMaxAge;
private List<String> defaultAcrValues;
private Integer minimumAcrLevel;
private Boolean minimumAcrLevelAutoresolve;
private List<String> minimumAcrPriorityList;
private String initiateLoginUri;
private List<String> groups;
private List<String> postLogoutRedirectUris;
Expand Down Expand Up @@ -154,6 +157,7 @@ public RegisterRequest() {
this.grantTypes = new ArrayList<>();
this.contacts = new ArrayList<>();
this.defaultAcrValues = new ArrayList<>();
this.minimumAcrPriorityList = new ArrayList<>();
this.postLogoutRedirectUris = new ArrayList<>();
this.groups = new ArrayList<>();
this.requestUris = new ArrayList<>();
Expand Down Expand Up @@ -1039,6 +1043,60 @@ public void setDefaultMaxAge(Integer defaultMaxAge) {
this.defaultMaxAge = defaultMaxAge;
}

/**
* Gets minimum acr level
*
* @return minimum acr level
*/
public Integer getMinimumAcrLevel() {
return minimumAcrLevel;
}

/**
* Sets minimum acr level
*
* @param minimumAcrLevel minimum acr level
*/
public void setMinimumAcrLevel(Integer minimumAcrLevel) {
this.minimumAcrLevel = minimumAcrLevel;
}

/**
* Gets minimum acr level auto resolve
*
* @return minimum acr level auto resolve
*/
public Boolean getMinimumAcrLevelAutoresolve() {
return minimumAcrLevelAutoresolve;
}

/**
* Sets minimum acr level auto resolve
*
* @param minimumAcrLevelAutoresolve minimum acr level auto resolve
*/
public void setMinimumAcrLevelAutoresolve(Boolean minimumAcrLevelAutoresolve) {
this.minimumAcrLevelAutoresolve = minimumAcrLevelAutoresolve;
}

/**
* Gets minimum acr priority list
*
* @return minimum acr priority list
*/
public List<String> getMinimumAcrPriorityList() {
return minimumAcrPriorityList;
}

/**
* Sets minimum acr priority list
*
* @param minimumAcrPriorityList minimum acr priority list
*/
public void setMinimumAcrPriorityList(List<String> minimumAcrPriorityList) {
this.minimumAcrPriorityList = minimumAcrPriorityList;
}

/**
* Returns the Default requested Authentication Context Class Reference values.
*
Expand Down Expand Up @@ -1379,6 +1437,9 @@ public static RegisterRequest fromJson(JSONObject requestObject) throws JSONExce
result.setPostLogoutRedirectUris(extractListByKey(requestObject, POST_LOGOUT_REDIRECT_URIS.toString()));
result.setGroups(extractListByKey(requestObject, GROUPS.toString()));
result.setDefaultAcrValues(extractListByKey(requestObject, DEFAULT_ACR_VALUES.toString()));
result.setMinimumAcrLevel(integerOrNull(requestObject, MINIMUM_ACR_LEVEL.toString()));
result.setMinimumAcrLevelAutoresolve(requestObject.optBoolean(MINIMUM_ACR_LEVEL_AUTORESOLVE.toString()));
result.setMinimumAcrPriorityList(extractListByKey(requestObject, MINIMUM_ACR_PRIORITY_LIST.toString()));
result.setFrontChannelLogoutUri(requestObject.optString(FRONT_CHANNEL_LOGOUT_URI.toString()));
result.setFrontChannelLogoutSessionRequired(requestObject.optBoolean(FRONT_CHANNEL_LOGOUT_SESSION_REQUIRED.toString()));
result.setBackchannelLogoutUris(extractListByKey(requestObject, BACKCHANNEL_LOGOUT_URI.toString()));
Expand Down Expand Up @@ -1588,6 +1649,15 @@ public void getParameters(BiFunction<String, Object, Void> function) {
if (defaultAcrValues != null && !defaultAcrValues.isEmpty()) {
function.apply(DEFAULT_ACR_VALUES.toString(), toJSONArray(defaultAcrValues));
}
if (minimumAcrLevel != null) {
function.apply(MINIMUM_ACR_LEVEL.toString(), minimumAcrLevel.toString());
}
if (minimumAcrLevelAutoresolve != null) {
function.apply(MINIMUM_ACR_LEVEL_AUTORESOLVE.toString(), minimumAcrLevelAutoresolve.toString());
}
if (minimumAcrPriorityList != null) {
function.apply(MINIMUM_ACR_PRIORITY_LIST.toString(), toJSONArray(minimumAcrPriorityList));
}
if (StringUtils.isNotBlank(initiateLoginUri)) {
function.apply(INITIATE_LOGIN_URI.toString(), initiateLoginUri);
}
Expand Down
3 changes: 2 additions & 1 deletion jans-auth-server/common/src/test/resources/testng.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="oxAuthCommon" parallel="false">
<test name="Audience Test" enabled="true">
<test name="Unit Tests" enabled="true">
<classes>
<class name="io.jans.as.common.AudienceTest"/>
<class name="io.jans.as.common.util.RedirectUriTest"/>
<class name="io.jans.as.common.model.registration.ClientSerializationTest"/>
<class name="io.jans.as.common.service.common.UserServiceTest"/>
<class name="io.jans.as.common.service.common.InumServiceTest"/>
</classes>
Expand Down
38 changes: 37 additions & 1 deletion jans-auth-server/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,18 @@ paths:
processing requests from the Client.
items:
type: string
minimum_acr_level:
type: integer
description: Integer value which sets minimum acr level.
example: 10
minimum_acr_level_autoresolve:
type: boolean
description: boolean value, if false and minimum_acr_level is higher then current acr_values then reject request. If true - resolve acr according to either client's minimum_acr_priority_list or AS auth_level_mapping
minimum_acr_priority_list:
type: array
description: enables client to specify the acr order of preference, rather then just the next lowest integer value
items:
type: string
groups:
type: array
description: Array of client's groups.
Expand Down Expand Up @@ -1614,6 +1626,18 @@ paths:
processing requests from the Client.
items:
type: string
minimum_acr_level:
type: integer
description: Integer value which sets minimum acr level.
example: 10
minimum_acr_level_autoresolve:
type: boolean
description: boolean value, if false and minimum_acr_level is higher then current acr_values then reject request. If true - resolve acr according to either client's minimum_acr_priority_list or AS auth_level_mapping
minimum_acr_priority_list:
type: array
description: enables client to specify the acr order of preference, rather then just the next lowest integer value
items:
type: string
initiate_login_uri:
type: string
description: Specifies the URI using the https scheme that the authorization server can call to initiate a login at the client.
Expand Down Expand Up @@ -1956,6 +1980,18 @@ paths:
processing requests from the Client.
items:
type: string
minimum_acr_level:
type: integer
description: Integer value which sets minimum acr level.
example: 10
minimum_acr_level_autoresolve:
type: boolean
description: boolean value, if false and minimum_acr_level is higher then current acr_values then reject request. If true - resolve acr according to either client's minimum_acr_priority_list or AS auth_level_mapping
minimum_acr_priority_list:
type: array
description: enables client to specify the acr order of preference, rather then just the next lowest integer value
items:
type: string
initiate_login_uri:
type: string
description: Specifies the URI using the https scheme that the authorization server can call to initiate a login at the client.
Expand Down Expand Up @@ -4282,7 +4318,7 @@ paths:
- SSA
summary: Create SSA.
description: Create `SSA` for the organization with `expiration` (optional).
operationId: post-register
operationId: post-register-ssa
security:
- bearer: [ ]
requestBody:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,24 @@ public enum RegisterRequestParam {
*/
DEFAULT_ACR_VALUES("default_acr_values"),

/**
* Integer value which sets minimum acr level.
*/
MINIMUM_ACR_LEVEL("minimum_acr_level"),

/**
* Boolean value,
* - if false and minimumAcrLevel is higher then current acr_values then reject request
* - if true - resolve acr according to either client's minimumAcrPriorityList or AS auth_level_mapping
*/
MINIMUM_ACR_LEVEL_AUTORESOLVE("minimum_acr_level_autoresolve"),

/**
* Array of strings,
* - enables client to specify the acr order of preference, rather then just the next lowest integer value
*/
MINIMUM_ACR_PRIORITY_LIST("minimum_acr_priority_list"),

/**
* URI using the https scheme that the Authorization Server can call to initiate a login at the Client.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,41 @@ public class ClientAttributes implements Serializable {
@JsonProperty("allowOfflineAccessWithoutConsent")
private Boolean allowOfflineAccessWithoutConsent;

@JsonProperty("minimumAcrLevel")
private Integer minimumAcrLevel = -1;

@JsonProperty("minimumAcrLevelAutoresolve")
private Boolean minimumAcrLevelAutoresolve;

@JsonProperty("minimumAcrPriorityList")
private List<String> minimumAcrPriorityList;

public Boolean getMinimumAcrLevelAutoresolve() {
return minimumAcrLevelAutoresolve;
}

public void setMinimumAcrLevelAutoresolve(Boolean minimumAcrLevelAutoresolve) {
this.minimumAcrLevelAutoresolve = minimumAcrLevelAutoresolve;
}

public List<String> getMinimumAcrPriorityList() {
if (minimumAcrPriorityList == null) minimumAcrPriorityList = new ArrayList<>();
return minimumAcrPriorityList;
}

public void setMinimumAcrPriorityList(List<String> minimumAcrPriorityList) {
this.minimumAcrPriorityList = minimumAcrPriorityList;
}

public Integer getMinimumAcrLevel() {
if (minimumAcrLevel == null) minimumAcrLevel = -1;
return minimumAcrLevel;
}

public void setMinimumAcrLevel(Integer minimumAcrLevel) {
this.minimumAcrLevel = minimumAcrLevel;
}

public Boolean getAllowOfflineAccessWithoutConsent() {
return allowOfflineAccessWithoutConsent;
}
Expand Down Expand Up @@ -378,6 +413,9 @@ public String toString() {
", publicSubjectIdentifierAttribute=" + publicSubjectIdentifierAttribute +
", redirectUrisRegex=" + redirectUrisRegex +
", allowOfflineAccessWithoutConsent=" + allowOfflineAccessWithoutConsent +
", minimumAcrLevel=" + minimumAcrLevel +
", minimumAcrLevelAutoresolve=" + minimumAcrLevelAutoresolve +
", minimumAcrPriorityList=" + minimumAcrPriorityList +
", defaultPromptLogin=" + defaultPromptLogin +
'}';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ private ResponseBuilder authorize(AuthzRequest authzRequest) throws AcrChangedEx
authorizeRestWebServiceValidator.validate(authzRequest, responseTypes, client);
authorizeRestWebServiceValidator.validatePkce(authzRequest.getCodeChallenge(), authzRequest.getRedirectUriResponse());

authzRequestService.setDefaultAcrsIfNeeded(authzRequest, client);
authzRequestService.setAcrsIfNeeded(authzRequest);

checkOfflineAccessScopes(responseTypes, prompts, client, scopes);
checkResponseType(authzRequest, responseTypes, client);
Expand Down
Loading

0 comments on commit b0034ec

Please sign in to comment.