Skip to content

Commit 6ab82b5

Browse files
committed
draft - work in progress
1 parent f69fba7 commit 6ab82b5

File tree

5 files changed

+506
-0
lines changed

5 files changed

+506
-0
lines changed

external-authn/README.md

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# External Authn
2+
3+
## Design
4+
```
5+
Title External Authn
6+
7+
actor Person
8+
participant Browser
9+
participant Website1
10+
participant Website2
11+
participant IDP
12+
database cache
13+
14+
Person->Browser: 1. Navigate to website1
15+
Browser->Website1:
16+
Website1->Browser: 2. redirect
17+
group Person Authn Script : Step One
18+
Browser->IDP: 3. [GET] /oxauth/authorize?client_id=__&redirect_uri=__&state=__\n&nonce=__&prompt=none&scope=__\n&response_mode=__&response_type=__
19+
IDP->IDP: 4. generate jans_key
20+
IDP<->cache: cache in session context\njans_key: {request params}
21+
IDP->Browser: 5. redirect /internal.idp?________\nSet Pre-Authn Session Cookie
22+
Browser->Website2:
23+
end
24+
Website2->Browser: 6. Display login page
25+
Person->Browser: 7. Enter Username / PW
26+
Browser->Website2: 8. (creds)
27+
group ROPW script
28+
Website2->IDP: 9. /oxauth/token?uid=__&pw="__&browser_ip=__&jans_key=__
29+
IDP->IDP: 10. update cache:\n "jans_key": "auth_success"
30+
IDP->IDP: 11. retreive user claims
31+
IDP->Website2:12. {\n "callback_url":"https://op-host/oxauth**/authorize?session_id={session_id}&redirect_uri={original_redirect}&...**",\n "userinfo": {"uid": "__",...}\n }
32+
end
33+
group Person Authn Script Step 2
34+
Website2->Browser: 13. write website 2 cookie;\n302 Location IDP callback_url
35+
Browser->IDP: 14. callback_url_from_step_12
36+
IDP->IDP: 15. get session context
37+
IDP->cache:16. delete jans_key\n lookup original redirect_uri
38+
IDP->Browser: 17. write IDP session cookie\nand 302: Location original redirect_uri
39+
end
40+
Browser->Website1:
41+
Website1->Website1: optional: 18 Validate id_token\n (claims optional)
42+
```
43+
![](external-authn-diagram.png)
44+
45+
Follow the instructions below to set up:
46+
47+
## oxAuth Configuration
48+
Above the **ox-auth** record of the **oxAuthConfiguration** table, enable a new attribute on the **oxAuthConfDynamic** field
49+
50+
Example:
51+
```
52+
"authorizationRequestCustomAllowedParameters": [
53+
{
54+
"paramName": "jansKey",
55+
"returnInResponse": false
56+
}
57+
]
58+
```
59+
60+
## Enable Custom Script
61+
62+
- ### Person Authentication - External Authn
63+
64+
Create a new record in table **oxCustomScript**.
65+
```
66+
INSERT INTO oxCustomScript ( doc_id, objectClass, dn, displayName, oxEnabled, oxRevision, oxScript, oxAlias, oxScriptType, oxModuleProperty, programmingLanguage, oxScriptError, oxConfigurationProperty, inum, description, oxLevel )
67+
VALUES ( 'PA01-EA01', 'oxCustomScript', 'inum=PA01-EA01,ou=scripts,o=gluu', 'pa-external-authn', 0, 1, '', '{"v": []}', 'person_authentication', '{"v": ["{\\"value1\\":\\"usage_type\\",\\"value2\\":\\"interactive\\",\\"description\\":\\"\\"}", "{\\"value1\\":\\"location_type\\",\\"value2\\":\\"ldap\\",\\"description\\":\\"\\"}"]}', 'python', NULL, '{"v": ["{\\"value1\\":\\"urlstep1\\",\\"value2\\":\\"http://demoexample.net:81\\",\\"hide\\":false,\\"description\\":\\"Url to return in step 1\\"}"]}', 'PA01-EA01', 'PA External Authn', 10 );
68+
```
69+
70+
Modify the **oxConfigurationProperty** field by replacing **URL_REDIRECT_URI** with the url that you want to return to the first step
71+
```
72+
'{"v": ["{\\"value1\\":\\"urlstep1\\",\\"value2\\":\\"{URL_REDIRECT_URI}\\",\\"hide\\":false,\\"description\\":\\"Url to return in step 1\\"}"]}'
73+
```
74+
75+
Modify the **oxScript** field by adding the content of the following link: [PersonAuthentication Script](pa-external-authn.py)
76+
77+
- ### ROPC (Resource Owner Password Credentials) Script - External Authn
78+
79+
Create a new record in table **oxCustomScript**.
80+
```
81+
INSERT INTO oxCustomScript ( doc_id, objectClass, dn, displayName, oxEnabled, oxRevision, oxScript, oxAlias, oxScriptType, oxModuleProperty, programmingLanguage, oxScriptError, oxConfigurationProperty, inum, description, oxLevel )
82+
VALUES ( 'ROPC-EA01', 'oxCustomScript', 'inum=ROPC-EA01,ou=scripts,o=gluu', 'ropc-external-authn', 0, 1, '', '{"v": []}', 'resource_owner_password_credentials', '{"v": ["{\\"value1\\":\\"location_type\\",\\"value2\\":\\"ldap\\",\\"description\\":\\"\\"}"]}', 'python', NULL, '{"v": []}', 'ROPC-EA01', 'ROPC External Authn', 1 );
83+
```
84+
85+
Modify the **oxScript** field by adding the content of the following link: [ROPC (Resource Owner Password Credentials) Script](ropc-external-authn.py)
86+
87+
- ### Update Token Script - External Authn
88+
89+
Create a new record in table **oxCustomScript**.
90+
```
91+
INSERT INTO oxCustomScript ( doc_id, objectClass, dn, displayName, oxEnabled, oxRevision, oxScript, oxAlias, oxScriptType, oxModuleProperty, programmingLanguage, oxScriptError, oxConfigurationProperty, inum, description, oxLevel )
92+
VALUES ( 'UPDT-EA01', 'oxCustomScript', 'inum=UPDT-EA01,ou=scripts,o=gluu', 'update-token-external-authn', 0, 1, '', '{"v": []}', 'update_token', '{"v": ["{\\"value1\\":\\"location_type\\",\\"value2\\":\\"ldap\\",\\"description\\":\\"\\"}"]}', 'python', NULL, '{"v": []}', 'UPDT-EA01', 'Update token External Authn', 1 );
93+
```
94+
95+
Modify the **oxScript** field by adding the content of the following link: [Update Token Script](ut-external-authn.py)
96+
97+
In this script you can choose whether to use the header or payload of the **id_token** for the **callback_url**:
98+
```
99+
jsonWebResponse.getHeader().setClaim("callback_url", jsonValCallbackUrl)
100+
jsonWebResponse.getClaims().setClaim("callback_url", jsonValCallbackUrl)
101+
```
102+
103+
## Enable custom script on the Client
104+
In the table **oxAuthClient** modify the field **oxAttributes** associating the custom scripts configured previously
105+
```
106+
"updateTokenScriptDns": ["inum=UPDT-EA01,ou=scripts,o=gluu"],
107+
"ropcScripts": ["inum=ROPC-EA01,ou=scripts,o=gluu"],
108+
```
109+
110+
And in the field **oxAuthDefaultAcrValues** add this value:
111+
```
112+
{"v": ["pa-external-authn"]}
113+
```
114+
115+
## Call Flow
116+
- ### Step 1: /authorize
117+
Request:
118+
```
119+
curl --location --request GET 'https://{your-gluu-url}/oxauth/restv1/authorize?response_type=code&client_id=14e36e18-1d51-41ac-a4cf-a7dc677f53a5&scope=openid+profile+address+email&redirect_uri=https://jans.localhost/jans-auth-rp/home.htm&state=a84dd61f-533c-46a4-9315-a66fda3e9a4e&nonce=80e6bd2b-eb78-48b9-be9c-6bb33ef80991&ui_locales=&claims_locales=&request_session_id=false&acr_values='
120+
```
121+
Response: (return the **redirect_uri** with jansKey)
122+
```
123+
http://demoexample.net:81?jansKey=46340f40-a554-46b1-9246-37c2e869919f
124+
```
125+
126+
- ### Step 2: /token
127+
Request: (**Authorization** = Basic base64(client_id:client_secret))
128+
```
129+
curl --location --request POST 'https://{your-gluu-url}/oxauth/restv1/token' \
130+
--header 'Authorization: Basic MTRlMzZlMTgtMWQ1MS00MWFjLWE0Y2YtYTdkYzY3N2Y1M2E1Ojk5NzE4NWU1LTc2NGUtNGE4Yi1hNjYwLTdjZmQ4NzJhNjc0Ng==' \
131+
--header 'Content-Type: application/x-www-form-urlencoded' \
132+
--data-urlencode 'grant_type=password' \
133+
--data-urlencode 'username=test_user' \
134+
--data-urlencode 'password=test_user_password' \
135+
--data-urlencode 'scope=openid' \
136+
--data-urlencode 'jansKey=46340f40-a554-46b1-9246-37c2e869919f'
137+
```
138+
Response: (id_token contains in header or payload callback_url)
139+
```
140+
{
141+
"access_token": "a0878887-b998-4da4-aa0b-4e74bd9a4441",
142+
"refresh_token": "d8b618ac-9d9c-4b90-9cac-aafb1e38e82e",
143+
"scope": "openid",
144+
"id_token": "eyJjYWxsYmFja191cmwiOiJodHRwczovL2phbnMubG9jYWxob3N0L2phbnMtYXV0aC9yZXN0djEvYXV0aG9yaXplP3Jlc3BvbnNlX3R5cGU9Y29kZSZzZXNzaW9uX2lkPWI1MDFmNzg0LTY0MTAtNDIyYy1iYWQ0LWU0MTNiYTViMjI1NSZyZWRpcmVjdF91cmk9aHR0cHMlM0ElMkYlMkZqYW5zLmxvY2FsaG9zdCUyRmphbnMtYXV0aC1ycCUyRmhvbWUuaHRtJmNsaWVudF9pZD0xNGUzNmUxOC0xZDUxLTQxYWMtYTRjZi1hN2RjNjc3ZjUzYTUiLCJraWQiOiIxNmEyMmIwMy03YjUzLTQxY2QtYWE3OS01YjI1ZjNlY2QzOGNfc2lnX3JzMjU2IiwidHlwIjoiand0IiwiYWxnIjoiUlMyNTYifQ.eyJjYWxsYmFja191cmwiOiJodHRwczovL2phbnMubG9jYWxob3N0L2phbnMtYXV0aC9yZXN0djEvYXV0aG9yaXplP3Jlc3BvbnNlX3R5cGU9Y29kZSZzZXNzaW9uX2lkPWI1MDFmNzg0LTY0MTAtNDIyYy1iYWQ0LWU0MTNiYTViMjI1NSZyZWRpcmVjdF91cmk9aHR0cHMlM0ElMkYlMkZqYW5zLmxvY2FsaG9zdCUyRmphbnMtYXV0aC1ycCUyRmhvbWUuaHRtJmNsaWVudF9pZD0xNGUzNmUxOC0xZDUxLTQxYWMtYTRjZi1hN2RjNjc3ZjUzYTUiLCJhdWQiOiIxNGUzNmUxOC0xZDUxLTQxYWMtYTRjZi1hN2RjNjc3ZjUzYTUiLCJhY3IiOiJzaW1wbGVfcGFzc3dvcmRfYXV0aCIsInN1YiI6InpMM3FrWFVwZE9OOXoxRDNNVUkyRG1CTHd3MzA1RUt4eWY3al8zb0oyaDQiLCJjb2RlIjoiNzg4OTA4ZTAtMmM3MC00YjE1LWFkZmUtYWZlMDBiMTgyMTkxIiwiYW1yIjpbXSwiaXNzIjoiaHR0cHM6Ly9qYW5zLmxvY2FsaG9zdCIsImV4cCI6MTY1OTc1ODA4MywiZ3JhbnQiOiJwYXNzd29yZCIsImlhdCI6MTY1OTc1NDQ4Mywic2lkIjoiODA0OGZjYmYtM2RjNC00YjFhLTgwYjktNmU1NTkzZTJhOWMwIiwib3hPcGVuSURDb25uZWN0VmVyc2lvbiI6Im9wZW5pZGNvbm5lY3QtMS4wIn0.u0sK9Yccf-P0OLQe0cKz75dF3cKQzQt9QpoHbqBsuIgXb4YwzDTWSuVM055USo5iO9P3KUiIGnMs6WPrZa-xcH84oKWsjF4TnAHdtwE_1xSofxDUU1nSdg8V3mRjHmZKWAvSmGtWTJFqTNGJKQsz1xrTpZ4ZAsI8Ey5OUNIhLsS6BIrFixLm3Sjufe4I2hiTtUPXb1PSYkPgHPZI00h8h4NDspPM9syufMbSLi-HN1aTQaJCONw2X-4KnvLGq1utX7qryclW1pq17W2j6Z49CjCW5ZtstK2p2FRoPwnInXNNr6vqSrpWR6pY9Uus7LHZZbg2DWKBASyfdjN6ecQaIw",
145+
"token_type": "Bearer",
146+
"expires_in": 299
147+
}
148+
```
149+
150+
- ### Step 3: callback_uri (/authorize)
151+
152+
Request:
153+
```
154+
curl --location --request GET 'https://{your-gluu-url}/oxauth/restv1/authorize?response_type=code&session_id=b501f784-6410-422c-bad4-e413ba5b2255&redirect_uri=https%3A%2F%2Fjans.localhost%2Fjans-auth-rp%2Fhome.htm&client_id=14e36e18-1d51-41ac-a4cf-a7dc677f53a5'
155+
```
156+
157+
Response: (return to the **redirect_uri**)
158+
```
159+
https://jans.localhost/jans-auth-rp/home.htm?code=441688df-8f36-4e2c-8174-18d23cc88049&acr_values=pa-external-authn&session_id=7ee59d72-d59a-49ce-a0cb-19c4fcfc404c&session_state=c3f595a892208e3d237722ad06d830f199295ccc355827c436fff71509401eae.a505421b-a332-4604-8772-6ca345c4a4b9
160+
```
215 KB
Loading
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# PersonAuthentication External Authn
2+
3+
from org.gluu.model.custom.script.type.auth import PersonAuthenticationType
4+
from org.gluu.service.cdi.util import CdiUtil
5+
from org.gluu.oxauth.security import Identity
6+
from org.gluu.oxauth.service import AuthenticationService
7+
from org.gluu.util import StringHelper
8+
from org.gluu.oxauth.util import ServerUtil
9+
from org.gluu.oxauth.service import SessionIdService
10+
from org.gluu.oxauth.service import CookieService
11+
from org.gluu.service.cache import CacheProvider
12+
from javax.faces.context import ExternalContext
13+
from java.util import HashMap
14+
from org.gluu.oxauth.service import UserService, RequestParameterService
15+
from org.gluu.oxauth.service.net import HttpService
16+
from javax.faces.context import FacesContext
17+
from org.gluu.jsf2.service import FacesService
18+
19+
import java
20+
import uuid
21+
22+
class PersonAuthentication(PersonAuthenticationType):
23+
def __init__(self, currentTimeMillis):
24+
self.currentTimeMillis = currentTimeMillis
25+
26+
def init(self, customScript, configurationAttributes):
27+
print "PA External Authn. Initialization"
28+
print "PA External Authn. Initialized successfully configurationAttributes = %s" % configurationAttributes
29+
30+
self.url_step1 = None
31+
32+
# Get Custom Properties
33+
try:
34+
self.url_step1 = configurationAttributes.get("urlstep1").getValue2()
35+
print "PA External Authn. Initialization. url_step1: '%s'" % self.url_step1
36+
except:
37+
print 'Missing required configuration attribute "urlstep1"'
38+
39+
return True
40+
41+
def destroy(self, configurationAttributes):
42+
print "PA External Authn. Destroy"
43+
print "PA External Authn. Destroyed successfully"
44+
return True
45+
46+
def getAuthenticationMethodClaims(self, requestParameters):
47+
return None
48+
49+
def getApiVersion(self):
50+
return 11
51+
52+
def isValidAuthenticationMethod(self, usageType, configurationAttributes):
53+
return True
54+
55+
def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes):
56+
return None
57+
58+
def authenticate(self, configurationAttributes, requestParameters, step):
59+
print "PA External Authn. Authenticate for step: %s" % step
60+
return True
61+
62+
def prepareForStep(self, configurationAttributes, requestParameters, step):
63+
if (step == 1):
64+
return True
65+
else:
66+
return False
67+
68+
def getExtraParametersForStep(self, configurationAttributes, step):
69+
return None
70+
71+
def getCountAuthenticationSteps(self, configurationAttributes):
72+
return 1
73+
74+
def getPageForStep(self, configurationAttributes, step):
75+
print "PA External Authn. GetPageForStep for step: %s" % step
76+
77+
externalContext = CdiUtil.bean(ExternalContext)
78+
sessionId = ServerUtil.getFirstValue(externalContext.getRequestParameterValuesMap(), "session_id")
79+
if (sessionId == None):
80+
# Retrieve sessionId from request parameters and validate it
81+
redirectUri = ServerUtil.getFirstValue(externalContext.getRequestParameterValuesMap(), "redirect_uri")
82+
if (redirectUri == None or StringHelper.isEmpty(redirectUri)):
83+
print "PA External Authn. GetPageForStep redirect_uri is null or empty"
84+
return ""
85+
print "PA External Authn. GetPageForStep redirect_uri '%s' found in request parameters" % redirectUri
86+
87+
clientId = ServerUtil.getFirstValue(externalContext.getRequestParameterValuesMap(), "client_id")
88+
if (clientId == None or StringHelper.isEmpty(clientId)):
89+
print "PA External Authn. GetPageForStep client_id is null or empty"
90+
return ""
91+
print "PA External Authn. GetPageForStep client_id '%s' found in request parameters" % clientId
92+
93+
# Generate jansKey
94+
jansKey = str(uuid.uuid4());
95+
print "PA External Authn. GetPageForStep jansKey '%s' generated" % jansKey
96+
97+
# Create JSON Values
98+
jsonValues = {}
99+
jsonValues["redirectUri"] = str(redirectUri)
100+
jsonValues["clientId"] = str(clientId)
101+
102+
cacheProvider = CdiUtil.bean(CacheProvider)
103+
cacheProvider.put(300, jansKey, jsonValues)
104+
print "PA External Authn. GetPageForStep jansKey '%s' added to cache: %s" % (jansKey, jsonValues)
105+
106+
requestParameterService = CdiUtil.bean(RequestParameterService)
107+
parametersMap = HashMap()
108+
parametersMap.put("jansKey", jansKey)
109+
callBackUrl = requestParameterService.parametersAsString(parametersMap)
110+
callBackUrl = "%s?%s" % (self.url_step1, callBackUrl)
111+
112+
print "PA External Authn. GetPageForStep redirect to %s" % callBackUrl
113+
114+
facesService = CdiUtil.bean(FacesService)
115+
facesService.redirectToExternalURL(callBackUrl)
116+
117+
return ""
118+
119+
return "postlogin.xhtml"
120+
121+
def getNextStep(self, configurationAttributes, requestParameters, step):
122+
return -1
123+
124+
def getLogoutExternalUrl(self, configurationAttributes, requestParameters):
125+
return None
126+
127+
def logout(self, configurationAttributes, requestParameters):
128+
return True

0 commit comments

Comments
 (0)