Skip to content

Commit

Permalink
Merge 8501e06 into 61be960
Browse files Browse the repository at this point in the history
  • Loading branch information
williamhaley committed Apr 13, 2021
2 parents 61be960 + 8501e06 commit 19b185f
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,5 @@ keys
tests/resources/keys/*.pem

.DS_Store
.vscode
build.sh
.vscode
18 changes: 18 additions & 0 deletions fence/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
from fence.resources.openid.microsoft_oauth2 import (
MicrosoftOauth2Client as MicrosoftClient,
)
from fence.resources.openid.okta_oauth2 import OktaOauth2Client as OktaClient
from fence.resources.openid.generic_oauth2 import GenericOauth2Client as GenericClient
from fence.resources.openid.orcid_oauth2 import OrcidOauth2Client as ORCIDClient
from fence.resources.openid.synapse_oauth2 import SynapseOauth2Client as SynapseClient
from fence.resources.openid.ras_oauth2 import RASOauth2Client as RASClient
Expand Down Expand Up @@ -358,6 +360,22 @@ def _setup_oidc_clients(app):
logger=logger,
)

# Add OIDC client for Okta if configured
if "okta" in oidc:
app.okta_client = OktaClient(
config["OPENID_CONNECT"]["okta"],
HTTP_PROXY=config.get("HTTP_PROXY"),
logger=logger,
)

# Add OIDC client for generic IDP if configured
if "generic" in oidc:
app.generic_client = GenericClient(
config["OPENID_CONNECT"]["generic"],
HTTP_PROXY=config.get("HTTP_PROXY"),
logger=logger,
)

# Add OIDC client for Amazon Cognito if configured.
if "cognito" in oidc:
app.cognito_client = CognitoClient(
Expand Down
16 changes: 16 additions & 0 deletions fence/blueprints/login/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
from fence.blueprints.login.google import GoogleLogin, GoogleCallback
from fence.blueprints.login.shib import ShibbolethLogin, ShibbolethCallback
from fence.blueprints.login.microsoft import MicrosoftLogin, MicrosoftCallback
from fence.blueprints.login.okta import OktaLogin, OktaCallback
from fence.blueprints.login.generic import GenericLogin, GenericCallback
from fence.blueprints.login.orcid import ORCIDLogin, ORCIDCallback
from fence.blueprints.login.ras import RASLogin, RASCallback
from fence.blueprints.login.synapse import SynapseLogin, SynapseCallback
Expand All @@ -34,6 +36,8 @@
"orcid": "orcid",
"synapse": "synapse",
"microsoft": "microsoft",
"okta": "okta",
"generic": "generic",
"cognito": "cognito",
"ras": "ras",
}
Expand Down Expand Up @@ -275,6 +279,18 @@ def provider_info(login_details):
MicrosoftCallback, "/microsoft/login", strict_slashes=False
)

if "okta" in configured_idps:
blueprint_api.add_resource(OktaLogin, "/okta", strict_slashes=False)
blueprint_api.add_resource(
OktaCallback, "/okta/login", strict_slashes=False
)

if "generic" in configured_idps:
blueprint_api.add_resource(GenericLogin, "/generic", strict_slashes=False)
blueprint_api.add_resource(
GenericCallback, "/generic/login", strict_slashes=False
)

if "cognito" in configured_idps:
blueprint_api.add_resource(CognitoLogin, "/cognito", strict_slashes=False)
blueprint_api.add_resource(
Expand Down
21 changes: 21 additions & 0 deletions fence/blueprints/login/generic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import flask

from fence.models import IdentityProvider
from fence.resources.openid.generic_oauth2 import GENERIC_IDP_NAME
from fence.blueprints.login.base import DefaultOAuth2Login, DefaultOAuth2Callback


class GenericLogin(DefaultOAuth2Login):
def __init__(self):
super(GenericLogin, self).__init__(
idp_name=GENERIC_IDP_NAME,
client=flask.current_app.generic_client,
)


class GenericCallback(DefaultOAuth2Callback):
def __init__(self):
super(GenericCallback, self).__init__(
idp_name=GENERIC_IDP_NAME,
client=flask.current_app.generic_client,
)
21 changes: 21 additions & 0 deletions fence/blueprints/login/okta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import flask

from fence.models import IdentityProvider
from fence.resources.openid.okta_oauth2 import OKTA_IDP_NAME
from fence.blueprints.login.base import DefaultOAuth2Login, DefaultOAuth2Callback


class OktaLogin(DefaultOAuth2Login):
def __init__(self):
super(OktaLogin, self).__init__(
idp_name=OKTA_IDP_NAME,
client=flask.current_app.okta_client,
)


class OktaCallback(DefaultOAuth2Callback):
def __init__(self):
super(OktaCallback, self).__init__(
idp_name=OKTA_IDP_NAME,
client=flask.current_app.okta_client,
)
18 changes: 18 additions & 0 deletions fence/config-default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,19 @@ OPENID_CONNECT:
# WARNING: DO NOT ENABLE IN PRODUCTION (for testing purposes only)
mock: false
mock_default_user: 'test@example.com'
# For information on configuring an Okta tenant as an OIDC IdP refer to Okta documentation at:
# https://developer.okta.com/docs/reference/api/oidc/#2-okta-as-the-identity-platform-for-your-app-or-api
okta:
discovery_url: ''
client_id: ''
client_secret: ''
redirect_url: '{{BASE_URL}}/login/okta/login/'
# generic is for use with an OIDC compliant IdP. It requires the discover URL to parse the various OIDC endpoints required.
generic:
discovery_url: ''
client_id: ''
client_secret: ''
redirect_url: '{{BASE_URL}}/login/generic/login/'
cognito:
# You must create a user pool in order to have a discovery url
discovery_url: 'https://cognito-idp.{REGION}.amazonaws.com/{USER-POOL-ID}/.well-known/openid-configuration'
Expand Down Expand Up @@ -257,6 +270,11 @@ LOGIN_OPTIONS: [] # !!! remove the empty list to enable login options!
# idp: orcid
# - name: 'Microsoft Login'
# idp: microsoft
# - name: 'Okta Login'
# idp: okta
# Generic Login: You may want to edit the name to reflect your OIDC idP.
# - name: 'Generic Login'
# idp: generic
# # Cognito login: You may want to edit the name to reflect Cognito's IdP,
# # especially if Cognito is only using one IdP
# - name: 'Login from Cognito'
Expand Down
50 changes: 50 additions & 0 deletions fence/resources/openid/generic_oauth2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import json
from .idp_oauth2 import Oauth2ClientBase

GENERIC_IDP_NAME = "generic"

class GenericOauth2Client(Oauth2ClientBase):

def __init__(self, settings, logger, HTTP_PROXY=None):
super(GenericOauth2Client, self).__init__(
settings,
logger,
scope="openid email",
discovery_url=settings["discovery_url"],
idp="Generic",
HTTP_PROXY=HTTP_PROXY,
)

def get_auth_url(self):
"""
Get authorization uri from discovery doc
"""
authorization_endpoint = self.get_value_from_discovery_doc(
"authorization_endpoint",
"",
)
uri, _ = self.session.create_authorization_url(
authorization_endpoint, prompt="login"
)

return uri

def get_user_id(self, code):
try:
token_endpoint = self.get_value_from_discovery_doc(
"token_endpoint",
"",
)
jwks_endpoint = self.get_value_from_discovery_doc(
"jwks_uri",
"",
)
claims = self.get_jwt_claims_identity(token_endpoint, jwks_endpoint, code)

if claims["email"]:
return {"email": claims["email"]}
else:
return {"error": "Can't get user's email!"}
except Exception as e:
self.logger.exception("Can't get user info")
return {"error": "Can't get your email: {}".format(e)}
50 changes: 50 additions & 0 deletions fence/resources/openid/okta_oauth2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import json
from .idp_oauth2 import Oauth2ClientBase

OKTA_IDP_NAME = "okta"

class OktaOauth2Client(Oauth2ClientBase):

def __init__(self, settings, logger, HTTP_PROXY=None):
super(OktaOauth2Client, self).__init__(
settings,
logger,
scope="openid email",
discovery_url=settings["discovery_url"],
idp="Okta",
HTTP_PROXY=HTTP_PROXY,
)

def get_auth_url(self):
"""
Get authorization uri from discovery doc
"""
authorization_endpoint = self.get_value_from_discovery_doc(
"authorization_endpoint",
"",
)
uri, _ = self.session.create_authorization_url(
authorization_endpoint, prompt="login"
)

return uri

def get_user_id(self, code):
try:
token_endpoint = self.get_value_from_discovery_doc(
"token_endpoint",
"",
)
jwks_endpoint = self.get_value_from_discovery_doc(
"jwks_uri",
"",
)
claims = self.get_jwt_claims_identity(token_endpoint, jwks_endpoint, code)

if claims["email"]:
return {"email": claims["email"]}
else:
return {"error": "Can't get user's email!"}
except Exception as e:
self.logger.exception("Can't get user info")
return {"error": "Can't get your email: {}".format(e)}

0 comments on commit 19b185f

Please sign in to comment.