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

chore(agama): refactor agama to use acr_values instead of agama_flow #8354

Merged
merged 3 commits into from
Apr 20, 2024
Merged
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
8 changes: 1 addition & 7 deletions docs/admin/developer/agama/engine-bridge-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,4 @@ Please account additional behaviors:

## Bridge configuration

There are a few configuration properties admins can set to modify the behavior of the bridge:

- `cust_param_name`: The name of the request parameter - in the authentication request - that will carry the name of the flow to launch. Ensure to register the given parameter name in the [server configuration](../../config-guide/jans-authorization-server-config.md) (property `authorizationRequestCustomAllowedParameters`) beforehand

- `default_flow_name`: If the relying party (RP) is not able to send custom parameters or omits the flow name in the authentication request, the value of this property will be assumed to be the flow to launch by default

- `finish_userid_db_attribute`: It is used to map the identity of the user to login in the case of sucessfully finished flows. The value of this property will contain a physical database attribute that will be correlated with the `userId` passed in the `Finish` instruction of the flow
Administrators can modify the behavior of the bridge by setting the `finish_userid_db_attribute` configuration property of the script. This is used to map the identity of the user to login in the case of sucessfully finished flows. The value of this property will contain a physical database attribute that will be correlated with the `userId` passed in the `Finish` instruction of the flow.
10 changes: 3 additions & 7 deletions docs/admin/developer/agama/jans-agama-engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,13 @@ The rest of this document describes implementation-specific details of the engin

## Launching flows

Flows can be launched by sending an (OpenId Connect) authentication request to the user's browser. This usually boils down to make a redirection to a URL looking like `https://<jans-server-name>/jans-auth/restv1/authorize?acr_values=agama&agama_flow=flow-qname&scope=...&response_type=...&redirect_uri=https...&client_id=...&state=...`. Check the OpenId Connect [spec](https://openid.net/specs/openid-connect-core-1_0.html) for more details. Note Jans Server is spec-compliant.
Flows can be launched by sending an (OpenId Connect) authentication request to the user's browser. This usually boils down to making a redirection to a URL looking like `https://<jans-server-name>/jans-auth/restv1/authorize?acr_values=agama_flowQname&scope=...&response_type=...&redirect_uri=https...&client_id=...&state=...`. Check the OpenId Connect [spec](https://openid.net/specs/openid-connect-core-1_0.html) for more details. Note Jans Server is spec-compliant.

Things to highlight:

- The `acr_values` parameter must be equal to `agama`
- The `acr_values` parameter carries the qualified name (identifier) of the flow to launch prefixed with the string `agama_`, for example `acr_values=agama_test.acme.co`

- The qualified name (identifier) of the flow to launch is passed using the parameter referenced in property `cust_param_name` of the Agama [bridge](./engine-bridge-config.md#bridge-configuration) script. `agama_flow` will most likely work since this is the default value employed by the Jans installer, e.g. `agama_flow=test.acme.co`

- If the flow to call receives input parameters, their values can be passed in the custom parameter as well. Use a hyphen to separate the flow name and the parameters expressed in JSON object format. For example, if the flow had inputs `height` and `color`, you can use `test.acme.co-{"height": 190, "color": "blue"}` for the value of `agama_flow`. Ensure to apply proper URL-encoding beforehand. In this case, the actual value would be `test-%7B%22height%22%3A+190%2C+%22color%22%3A+%22blue%22%7D`. If certain inputs are not provided, `null` values will be assigned for them

- If for some reason you are not able to set the given custom parameter in the authorization request, you can set its value in the configuration property `default_flow_name` of the [bridge](./engine-bridge-config.md#bridge-configuration) script. Note this will launch the same fixed flow at all times
- If the flow to call receives input parameters, this data can be appended to the `acr_values` parameter: use a hyphen to separate the flow name and the parameters expressed in Base64 URL encoded format. For example, if the flow had inputs `height` and `color`, you would encode the string `{"height": 190, "color": "blue"}` and the resulting value would be `agama_test.acme.co-eyJoZWlnaHQiOiAxOTAsICJjb2xvciI6ICJibHVlIn0`. When a given input variable is not provided, the engine will assign a `null` value automatically

## Authentication and `Finish`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from io.jans.agama import NativeJansFlowBridge
from io.jans.agama.engine.misc import FlowUtils
from io.jans.service import EncryptionService
from io.jans.as.model.util import Base64Util
from io.jans.as.server.security import Identity
from io.jans.as.server.service import AuthenticationService, UserService
from io.jans.jsf2.service import FacesService
Expand All @@ -29,26 +30,14 @@ def __init__(self, currentTimeMillis):
def init(self, customScript, configurationAttributes):
print "Agama. Initialization"
self.resultParam = "agamaData"

prop = "cust_param_name"
self.cust_param_name = self.configProperty(configurationAttributes, prop)

if self.cust_param_name == None:
print "Agama. Custom parameter name not referenced via property '%s'" % prop
return False

prop = "default_flow_name"
self.default_flow_name = self.configProperty(configurationAttributes, prop)

prop = "finish_userid_db_attribute"
self.finish_userid_db_attr = self.configProperty(configurationAttributes, prop)

if self.finish_userid_db_attr == None:
print "Agama. Property '%s' is missing value" % prop
return False

print "Agama. Request param '%s' will be used to pass flow name and inputs" % self.cust_param_name
print "Agama. When '%s' is missing, the flow to launch will be '%s'" % (self.cust_param_name, self.default_flow_name)

print "Agama. DB attribute '%s' will be used to map the identity of userId passed in Finish directives (if any)" % self.finish_userid_db_attr
print "Agama. Initialized successfully"

Expand Down Expand Up @@ -139,20 +128,19 @@ def prepareForStep(self, configurationAttributes, requestParameters, step):
print "Agama. Failed to retrieve session_id"
return False

param = session.getSessionAttributes().get(self.cust_param_name)
cesar = session.getSessionAttributes()
param = cesar.get("agama_flow")

if StringHelper.isEmpty(param):
print "Agama. Request param '%s' is missing or has no value" % self.cust_param_name

param = self.default_flow_name
if param == None:
print "Agama. Default flow name is not set either..."
param = self.extractAgamaFlow(cesar.get("acr_values"))

if StringHelper.isEmpty(param):
print "Agama. Unable to determine the Agama flow to launch. Check the docs"
return False

(qn, ins) = self.extractParams(param)
if qn == None:
print "Agama. Param '%s' is missing the name of the flow to be launched" % self.cust_param_name
print "Agama. Unable to determine the Agama flow to launch. Check the docs"
return False

try:
Expand Down Expand Up @@ -215,10 +203,16 @@ def setMessageError(self, severity, msg):
facesMessages.clear()
facesMessages.add(severity, msg)

def extractAgamaFlow(self, acr):
prefix = "agama_"
if StringHelper.isNotEmpty(acr) and acr.find(prefix) == 0:
return acr[len(prefix):]
return None

def extractParams(self, param):

# param must be of the form QN-INPUT where QN is the qualified name of the flow to launch
# INPUT is a JSON object that contains the arguments to use for the flow call.
# INPUT is a base64URL-encoded JSON object that contains the arguments to use for the flow call.
# The keys of this object should match the already defined flow inputs. Ideally, and
# depending on the actual flow implementation, some keys may not even be required
# QN and INPUTS are separated by a hyphen
Expand All @@ -230,4 +224,4 @@ def extractParams(self, param):
elif i == -1:
return (param, None)
else:
return (param[:i], param[i+1:])
return (param[:i], Base64Util.base64urldecodeToString(param[i+1:]))
4 changes: 0 additions & 4 deletions jans-auth-server/server/conf/jans-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -460,10 +460,6 @@
{
"paramName": "customParam5",
"returnInResponse": true
},
{
"paramName": "agama_flow",
"returnInResponse": false
}
],
"legacyDynamicRegistrationScopeParam": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,10 +499,6 @@
{
"paramName": "customParam5",
"returnInResponse": true
},
{
"paramName": "agama_flow",
"returnInResponse": false
}
],
"legacyDynamicRegistrationScopeParam": false,
Expand Down
2 changes: 0 additions & 2 deletions jans-linux-setup/jans_setup/templates/scripts.ldif
Original file line number Diff line number Diff line change
Expand Up @@ -570,8 +570,6 @@ objectClass: top
description: Agama Script
displayName: agama
inum: BADA-BADA
jansConfProperty: {"value1":"cust_param_name","value2":"agama_flow","description":""}
jansConfProperty: {"value1":"default_flow_name","value2":"","description":""}
jansConfProperty: {"value1":"finish_userid_db_attribute","value2":"uid","description":""}
jansEnabled: false
jansLevel: 10
Expand Down