-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add feature to include custom-claims in user-info endpoint of a…
…dmin-ui plugin #2969 (#2970) * feat: add feature to include custom-claims in user-info endpoint of admin-ui plugin #2969 * feat: add feature to include custom-claims in user-info endpoint of admin-ui plugin #2969 * feat: add feature to include custom-claims in user-info endpoint of admin-ui plugin #2969 * feat: add feature to include custom-claims in user-info endpoint of admin-ui plugin #2969
- Loading branch information
Showing
5 changed files
with
405 additions
and
1 deletion.
There are no files selected for viewing
87 changes: 87 additions & 0 deletions
87
docs/script-catalog/introspection/introspection-github-claims/introspection_github_claims.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. | ||
# Copyright (c) 2019, Janssen | ||
# | ||
# | ||
|
||
from io.jans.model.custom.script.type.introspection import IntrospectionType | ||
from io.jans.as.server.model.common import AuthorizationGrantList | ||
from io.jans.as.server.service import SessionIdService | ||
from io.jans.service.cdi.util import CdiUtil | ||
from java.lang import String | ||
|
||
class Introspection(IntrospectionType): | ||
def __init__(self, currentTimeMillis): | ||
self.currentTimeMillis = currentTimeMillis | ||
|
||
def init(self, customScript, configurationAttributes): | ||
print "Github. Introspection script. Initializing ..." | ||
print "Github. Introspection script. Initialized successfully" | ||
|
||
return True | ||
|
||
def destroy(self, configurationAttributes): | ||
print "Github. Introspection script. Destroying ..." | ||
print "Github. Introspection script. Destroyed successfully" | ||
return True | ||
|
||
def getApiVersion(self): | ||
return 11 | ||
|
||
# Returns boolean, true - apply introspection method, false - ignore it. | ||
# This method is called after introspection response is ready. This method can modify introspection response. | ||
# Note : | ||
# responseAsJsonObject - is org.codehaus.jettison.json.JSONObject, you can use any method to manipulate json | ||
# context is reference of io.jans.as.service.external.context.ExternalIntrospectionContext (in https://github.com/JanssenFederation/oxauth project, ) | ||
def modifyResponse(self, responseAsJsonObject, context): | ||
print "Github. Checking for saved parameters in session ..." | ||
try: | ||
token = context.getHttpRequest().getParameter("token") | ||
if token is None: | ||
print "Github. Introspection. There is no token in request" | ||
return True | ||
|
||
authorizationGrantList = CdiUtil.bean(AuthorizationGrantList) | ||
authorizationGrant = authorizationGrantList.getAuthorizationGrantByAccessToken(token) | ||
if authorizationGrant is None: | ||
print "Github. Introspection. Failed to load authorization grant by token" | ||
return False | ||
|
||
# Put user_id into response | ||
responseAsJsonObject.accumulate("user_id", authorizationGrant.getUser().getUserId()) | ||
|
||
# Put custom parameters into response | ||
sessionDn = authorizationGrant.getSessionDn(); | ||
print "sessionDn '%s'" % sessionDn | ||
if sessionDn is None: | ||
print "There is no session" | ||
return True | ||
|
||
sessionIdService = CdiUtil.bean(SessionIdService) | ||
session = sessionIdService.getSessionByDn(sessionDn, False) | ||
if sessionDn is None: | ||
print "Github. Introspection. Failed to load session '%s'" % sessionDn | ||
return False | ||
|
||
# Return session_id | ||
responseAsJsonObject.accumulate("session_id", sessionDn) | ||
|
||
sessionAttributes = session.getSessionAttributes() | ||
if sessionAttributes is None: | ||
print "There is no session attributes" | ||
return True | ||
|
||
# Append custom claims | ||
customClaims = {} | ||
|
||
if sessionAttributes.containsKey("gihub_username"): | ||
customClaims["gihub_username"] = sessionAttributes.get("gihub_username") | ||
if sessionAttributes.containsKey("gihub_access_token"): | ||
customClaims["gihub_access_token"] = sessionAttributes.get("gihub_access_token") | ||
|
||
responseAsJsonObject.accumulate("customClaims", customClaims) | ||
except Exception as e: | ||
print "Exception occured. Unable to resolve role/scope mapping." | ||
print e | ||
|
||
return True | ||
|
255 changes: 255 additions & 0 deletions
255
...atalog/person_authentication/github-external-authenticator/GithubExternalAuthenticator.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
# Janssen Project software is available under the Apache 2.0 License (2004). See http://www.apache.org/licenses/ for full text. | ||
# Copyright (c) 2020, Janssen Project | ||
# | ||
# Author: Yuriy Movchan | ||
# | ||
|
||
from io.jans.as.common.model.common import User | ||
from io.jans.as.model.jwt import Jwt | ||
from io.jans.as.server.service import AuthenticationService | ||
from io.jans.as.common.service.common import UserService | ||
from io.jans.as.server.service.net import HttpService | ||
from io.jans.as.server.security import Identity | ||
from io.jans.as.server.util import ServerUtil | ||
from io.jans.orm import PersistenceEntryManager | ||
from io.jans.as.persistence.model.configuration import GluuConfiguration | ||
from io.jans.model.custom.script.type.auth import PersonAuthenticationType | ||
from io.jans.service.cdi.util import CdiUtil | ||
from io.jans.util import StringHelper | ||
|
||
from io.jans.jsf2.service import FacesService | ||
from java.util import Arrays, UUID | ||
|
||
import json | ||
import sys | ||
import datetime | ||
import urllib | ||
|
||
class PersonAuthentication(PersonAuthenticationType): | ||
def __init__(self, currentTimeMillis): | ||
self.currentTimeMillis = currentTimeMillis | ||
|
||
def init(self, customScript, configurationAttributes): | ||
print "GitHub. Initialization" | ||
print "GitHub. Initialized successfully" | ||
|
||
# read config from github_creds_file | ||
github_creds_file = configurationAttributes.get("github_creds_file").getValue2() | ||
f = open(github_creds_file, 'r') | ||
try: | ||
creds = json.loads(f.read()) | ||
print creds | ||
except: | ||
print "GitHub: Initialization. Failed to load creds from file:", github_creds_file | ||
print "Exception: ", sys.exc_info()[1] | ||
return False | ||
finally: | ||
f.close() | ||
|
||
self.op_server = str(creds["op_server"]) | ||
self.client_id = str(creds["client_id"]) | ||
self.client_secret = str(creds["client_secret"]) | ||
self.authorization_uri = str(creds["authorization_uri"]) | ||
self.token_uri = str(creds["token_uri"]) | ||
self.userinfo_uri = str(creds["userinfo_uri"]) | ||
self.redirect_uri = str(creds["redirect_uri"]) | ||
self.scope = str(creds["scope"]) | ||
self.title = str(creds["title"]) | ||
self.auto_redirect = creds["auto_redirect"] | ||
|
||
print "GitHub: Initialized successfully" | ||
|
||
return True | ||
|
||
def destroy(self, configurationAttributes): | ||
print "GitHub. Destroy" | ||
print "GitHub. Destroyed successfully" | ||
return True | ||
|
||
def getAuthenticationMethodClaims(self, requestParameters): | ||
return None | ||
|
||
def getApiVersion(self): | ||
return 11 | ||
|
||
def isValidAuthenticationMethod(self, usageType, configurationAttributes): | ||
return True | ||
|
||
def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): | ||
return None | ||
|
||
def authenticate(self, configurationAttributes, requestParameters, step): | ||
print "GitHub: authenticate called for step %s" % str(step) | ||
identity = CdiUtil.bean(Identity) | ||
authenticationService = CdiUtil.bean(AuthenticationService) | ||
|
||
if step == 1: | ||
# Get Access Token | ||
tokenResponse = self.getToken(requestParameters) | ||
if tokenResponse is None: | ||
return False | ||
|
||
# Get User Info | ||
userInfo = self.getUserInfo(tokenResponse["access_token"]) | ||
foundUser = self.addUser(userInfo) | ||
if foundUser is None: | ||
return False | ||
|
||
identity.setWorkingParameter("gihub_username", userInfo["login"]) | ||
identity.setWorkingParameter("gihub_access_token", tokenResponse["access_token"]) | ||
|
||
print "GitHub: Successfully authenticated" | ||
|
||
loggedIn = authenticationService.authenticate(foundUser.getUserId()) | ||
print "GitHub: Authentication: %s" % str(loggedIn) | ||
return loggedIn | ||
|
||
def prepareForStep(self, configurationAttributes, requestParameters, step): | ||
print "GitHub: prepareForStep called for step %s" % str(step) | ||
if step == 1: | ||
# redirect to external OIDC server | ||
|
||
redirect_url_elements = [self.authorization_uri, | ||
"?response_type=code id_token", | ||
"&client_id=", self.client_id, | ||
"&scope=", self.scope, | ||
"&redirect_uri=", self.redirect_uri] | ||
redirect_url = "".join(redirect_url_elements) | ||
|
||
identity = CdiUtil.bean(Identity) | ||
|
||
if self.auto_redirect: | ||
facesService = CdiUtil.bean(FacesService) | ||
facesService.redirectToExternalURL(redirect_url) | ||
else: | ||
identity.setWorkingParameter("oidc_redirect_uri", redirect_url) | ||
identity.setWorkingParameter("oidc_title", self.title) | ||
|
||
return True | ||
|
||
def getExtraParametersForStep(self, configurationAttributes, step): | ||
print "GitHub: getExtraParametersForStep called for step %s" % str(step) | ||
return Arrays.asList("gihub_username", "gihub_access_token") | ||
|
||
def getCountAuthenticationSteps(self, configurationAttributes): | ||
print "GitHub: getCountAuthenticationSteps called" | ||
return 1 | ||
|
||
def getPageForStep(self, configurationAttributes, step): | ||
print "GitHub: getPageForStep called for step %s" % str(step) | ||
if(step == 1): | ||
return "/auth/github/github.xhtml" | ||
return "" | ||
|
||
def getNextStep(self, configurationAttributes, requestParameters, step): | ||
print "GitHub: getNextStep called for step %s" % str(step) | ||
return -1 | ||
|
||
def getLogoutExternalUrl(self, configurationAttributes, requestParameters): | ||
print "GitHub: Get external logout URL call" | ||
return None | ||
|
||
def logout(self, configurationAttributes, requestParameters): | ||
return True | ||
|
||
def generalLogin(self, identity, authenticationService): | ||
print "GitHub: general login" | ||
credentials = identity.getCredentials() | ||
user_name = credentials.getUsername() | ||
user_password = credentials.getPassword() | ||
|
||
logged_in = False | ||
if (StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password)): | ||
logged_in = authenticationService.authenticate(user_name, user_password) | ||
|
||
return logged_in | ||
|
||
def getLocalPrimaryKey(self): | ||
entryManager = CdiUtil.bean(PersistenceEntryManager) | ||
config = GluuConfiguration() | ||
config = entryManager.find(config.getClass(), "ou=configuration,o=jans") | ||
# Pick (one) attribute where user id is stored (e.g. uid/mail) | ||
# primaryKey is the primary key on the backend AD / LDAP Server | ||
# localPrimaryKey is the primary key on Janssen. This attr value has been mapped with the primary key attr of the backend AD / LDAP when configuring cache refresh | ||
uid_attr = config.getIdpAuthn().get(0).getConfig().findValue("localPrimaryKey").asText() | ||
print "GitHub: init. uid attribute is '%s'" % uid_attr | ||
return uid_attr | ||
|
||
def getToken(self, requestParameters): | ||
print "GitHub: Get Access Token" | ||
oidcCode = ServerUtil.getFirstValue(requestParameters, "code") | ||
httpService = CdiUtil.bean(HttpService) | ||
httpclient = httpService.getHttpsClient() | ||
tokenRequestData = urllib.urlencode({ | ||
"code" : oidcCode, | ||
"grant_type" : "authorization_code", | ||
"redirect_uri": self.redirect_uri, | ||
"client_id": self.client_id, | ||
"client_secret": self.client_secret | ||
}) | ||
|
||
tokenRequestHeaders = { "Content-type" : "application/x-www-form-urlencoded", "Accept" : "application/json" } | ||
|
||
resultResponse = httpService.executePost(httpclient, self.token_uri, None, tokenRequestHeaders, tokenRequestData) | ||
httpResponse = resultResponse.getHttpResponse() | ||
httpResponseStatusCode = httpResponse.getStatusLine().getStatusCode() | ||
print "OIDC: token response status code: %s" % httpResponseStatusCode | ||
if str(httpResponseStatusCode) != "200": | ||
print "OIDC: Failed to get token, status code %s" % httpResponseStatusCode | ||
return None | ||
|
||
responseBytes = httpService.getResponseContent(httpResponse) | ||
responseString = httpService.convertEntityToString(responseBytes) | ||
tokenResponse = json.loads(responseString) | ||
|
||
return tokenResponse | ||
|
||
def addUser(self, user): | ||
try: | ||
print "GitHub: Adding user" | ||
userId = user["login"] | ||
userService = CdiUtil.bean(UserService) | ||
foundUser = userService.getUserByAttribute("jansExtUid", "github:"+userId) | ||
|
||
if foundUser is None: | ||
print "GitHub: User not found, adding new" | ||
foundUser = User() | ||
foundUser.setAttribute("jansExtUid", "github:"+userId) | ||
foundUser.setAttribute("jansEmail", user["email"]) | ||
foundUser.setAttribute("mail", user["email"]) | ||
foundUser.setAttribute("displayName", "github:"+userId) | ||
foundUser.setAttribute("givenName", "github:"+userId) | ||
foundUser.setAttribute(self.getLocalPrimaryKey(), userId) | ||
foundUser = userService.addUser(foundUser, True) | ||
|
||
return foundUser | ||
except Exception as e: | ||
print e | ||
print "GitHub: Add user Exception: ", sys.exc_info()[1] | ||
return None | ||
|
||
def getUserInfo(self, accessToken): | ||
try: | ||
print "GitHub: Get Userinfo" | ||
httpService = CdiUtil.bean(HttpService) | ||
httpclient = httpService.getHttpsClient() | ||
tokenRequestHeaders = { "Authorization" : "Bearer %s" % accessToken, "Accept" : "application/json" } | ||
|
||
resultResponse = httpService.executeGet(httpclient, self.userinfo_uri, tokenRequestHeaders) | ||
httpResponse = resultResponse.getHttpResponse() | ||
httpResponseStatusCode = httpResponse.getStatusLine().getStatusCode() | ||
print "GitHub: userinfo response status code: %s" % httpResponseStatusCode | ||
if str(httpResponseStatusCode) != "200": | ||
print "GitHub: Failed to get userinfo, status code %s" % httpResponseStatusCode | ||
return None | ||
|
||
responseBytes = httpService.getResponseContent(httpResponse) | ||
responseString = httpService.convertEntityToString(responseBytes) | ||
userinfoResponse = json.loads(responseString) | ||
|
||
print userinfoResponse | ||
|
||
return userinfoResponse | ||
except Exception as e: | ||
print e | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.