Merge pull request #3414 from charhate/membership
Configurable user memberships endpoint
This commit is contained in:
commit
6fd7684d2d
|
@ -712,6 +712,33 @@ For more information about how to use social logins, see: `Satellizer <https://g
|
||||||
|
|
||||||
PING_AUTH_ENDPOINT = "https://<yourpingserver>/oauth2/authorize"
|
PING_AUTH_ENDPOINT = "https://<yourpingserver>/oauth2/authorize"
|
||||||
|
|
||||||
|
.. data:: PING_USER_MEMBERSHIP_URL
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
An optional additional endpoint to learn membership details post the user validation.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
PING_USER_MEMBERSHIP_URL = "https://<yourmembershipendpoint>"
|
||||||
|
|
||||||
|
.. data:: PING_USER_MEMBERSHIP_TLS_PROVIDER
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
A custom TLS session provider plugin name
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
PING_USER_MEMBERSHIP_TLS_PROVIDER = "slug-name"
|
||||||
|
|
||||||
|
.. data:: PING_USER_MEMBERSHIP_SERVICE
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
Membership service name used by PING_USER_MEMBERSHIP_TLS_PROVIDER to create a session
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
PING_USER_MEMBERSHIP_SERVICE = "yourmembershipservice"
|
||||||
|
|
||||||
.. data:: OAUTH2_SECRET
|
.. data:: OAUTH2_SECRET
|
||||||
:noindex:
|
:noindex:
|
||||||
|
|
||||||
|
|
|
@ -285,6 +285,17 @@ The `ExportPlugin` object requires the implementation of one function::
|
||||||
Support of various formats sometimes relies on external tools system calls. Always be mindful of sanitizing any input to these calls.
|
Support of various formats sometimes relies on external tools system calls. Always be mindful of sanitizing any input to these calls.
|
||||||
|
|
||||||
|
|
||||||
|
Custom TLS Provider
|
||||||
|
------
|
||||||
|
|
||||||
|
Managing TLS at the enterprise scale could be hard and often organizations offer custom wrapper implementations. It could
|
||||||
|
be ideal to use those while making calls to internal services. The `TLSPlugin` would help to achieve this. It requires the
|
||||||
|
implementation of one function which creates a TLS session::
|
||||||
|
|
||||||
|
def session(self, server_application):
|
||||||
|
# return active session
|
||||||
|
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
:license: Apache, see LICENSE for more details.
|
:license: Apache, see LICENSE for more details.
|
||||||
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
||||||
"""
|
"""
|
||||||
|
import json
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
import base64
|
import base64
|
||||||
import requests
|
import requests
|
||||||
|
@ -23,7 +25,7 @@ from lemur.roles import service as role_service
|
||||||
from lemur.logs import service as log_service
|
from lemur.logs import service as log_service
|
||||||
from lemur.auth.service import create_token, fetch_token_header, get_rsa_public_key
|
from lemur.auth.service import create_token, fetch_token_header, get_rsa_public_key
|
||||||
from lemur.auth import ldap
|
from lemur.auth import ldap
|
||||||
|
from lemur.plugins.base import plugins
|
||||||
|
|
||||||
mod = Blueprint("auth", __name__)
|
mod = Blueprint("auth", __name__)
|
||||||
api = Api(mod)
|
api = Api(mod)
|
||||||
|
@ -138,6 +140,47 @@ def retrieve_user(user_api_url, access_token):
|
||||||
return user, profile
|
return user, profile
|
||||||
|
|
||||||
|
|
||||||
|
def retrieve_user_memberships(user_api_url, user_membership_api_url, access_token):
|
||||||
|
user, profile = retrieve_user(user_api_url, access_token)
|
||||||
|
|
||||||
|
if user_membership_api_url is None:
|
||||||
|
return user, profile
|
||||||
|
"""
|
||||||
|
Potentially, below code can be made more generic i.e., plugin driven. Unaware of the usage of this
|
||||||
|
code across the community, current implementation is config driven. Without user_membership_api_url
|
||||||
|
configured, it is backward compatible.
|
||||||
|
"""
|
||||||
|
tls_provider = plugins.get(current_app.config.get("PING_USER_MEMBERSHIP_TLS_PROVIDER"))
|
||||||
|
|
||||||
|
# put user id in url
|
||||||
|
user_membership_api_url = user_membership_api_url.replace("%user_id%", profile["userId"])
|
||||||
|
|
||||||
|
session = tls_provider.session(current_app.config.get("PING_USER_MEMBERSHIP_SERVICE"))
|
||||||
|
headers = {"Content-Type": "application/json"}
|
||||||
|
data = {"relation": "DIRECT_ONLY", "groupFilter": {"type": "GOOGLE"}, "size": 500}
|
||||||
|
user_membership = {"email": profile["email"],
|
||||||
|
"thumbnailPhotoUrl": profile["thumbnailPhotoUrl"],
|
||||||
|
"googleGroups": []}
|
||||||
|
while True:
|
||||||
|
# retrieve information about the current user memberships
|
||||||
|
r = session.post(user_membership_api_url, data=json.dumps(data), headers=headers)
|
||||||
|
|
||||||
|
if r.status_code == 200:
|
||||||
|
response = r.json()
|
||||||
|
membership_details = response["data"]
|
||||||
|
for membership in membership_details:
|
||||||
|
user_membership["googleGroups"].append(membership["membership"]["name"])
|
||||||
|
|
||||||
|
if "nextPageToken" in response and response["nextPageToken"]:
|
||||||
|
data["nextPageToken"] = response["nextPageToken"]
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
current_app.logger.error(f"Response Code:{r.status_code} {r.text}")
|
||||||
|
break
|
||||||
|
return user, user_membership
|
||||||
|
|
||||||
|
|
||||||
def create_user_roles(profile):
|
def create_user_roles(profile):
|
||||||
"""Creates new roles based on profile information.
|
"""Creates new roles based on profile information.
|
||||||
|
|
||||||
|
@ -156,7 +199,7 @@ def create_user_roles(profile):
|
||||||
description="This is a google group based role created by Lemur",
|
description="This is a google group based role created by Lemur",
|
||||||
third_party=True,
|
third_party=True,
|
||||||
)
|
)
|
||||||
if not role.third_party:
|
if (group != 'admin') and (not role.third_party):
|
||||||
role = role_service.set_third_party(role.id, third_party_status=True)
|
role = role_service.set_third_party(role.id, third_party_status=True)
|
||||||
roles.append(role)
|
roles.append(role)
|
||||||
else:
|
else:
|
||||||
|
@ -375,7 +418,6 @@ class Ping(Resource):
|
||||||
|
|
||||||
# you can either discover these dynamically or simply configure them
|
# you can either discover these dynamically or simply configure them
|
||||||
access_token_url = current_app.config.get("PING_ACCESS_TOKEN_URL")
|
access_token_url = current_app.config.get("PING_ACCESS_TOKEN_URL")
|
||||||
user_api_url = current_app.config.get("PING_USER_API_URL")
|
|
||||||
|
|
||||||
secret = current_app.config.get("PING_SECRET")
|
secret = current_app.config.get("PING_SECRET")
|
||||||
|
|
||||||
|
@ -391,7 +433,12 @@ class Ping(Resource):
|
||||||
error_code = validate_id_token(id_token, args["clientId"], jwks_url)
|
error_code = validate_id_token(id_token, args["clientId"], jwks_url)
|
||||||
if error_code:
|
if error_code:
|
||||||
return error_code
|
return error_code
|
||||||
user, profile = retrieve_user(user_api_url, access_token)
|
|
||||||
|
user, profile = retrieve_user_memberships(
|
||||||
|
current_app.config.get("PING_USER_API_URL"),
|
||||||
|
current_app.config.get("PING_USER_MEMBERSHIP_URL"),
|
||||||
|
access_token
|
||||||
|
)
|
||||||
roles = create_user_roles(profile)
|
roles = create_user_roles(profile)
|
||||||
update_user(user, profile, roles)
|
update_user(user, profile, roles)
|
||||||
|
|
||||||
|
|
|
@ -3,3 +3,4 @@ from .issuer import IssuerPlugin # noqa
|
||||||
from .source import SourcePlugin # noqa
|
from .source import SourcePlugin # noqa
|
||||||
from .notification import NotificationPlugin, ExpirationNotificationPlugin # noqa
|
from .notification import NotificationPlugin, ExpirationNotificationPlugin # noqa
|
||||||
from .export import ExportPlugin # noqa
|
from .export import ExportPlugin # noqa
|
||||||
|
from .tls import TLSPlugin # noqa
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
"""
|
||||||
|
.. module: lemur.plugins.bases.tls
|
||||||
|
:platform: Unix
|
||||||
|
:copyright: (c) 2021 by Netflix Inc., see AUTHORS for more
|
||||||
|
:license: Apache, see LICENSE for more details.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sayali Charhate <scharhate@netflix.com>
|
||||||
|
"""
|
||||||
|
from lemur.plugins.base import Plugin
|
||||||
|
|
||||||
|
|
||||||
|
class TLSPlugin(Plugin):
|
||||||
|
"""
|
||||||
|
This is the base class from which all supported
|
||||||
|
tls session providers will inherit from.
|
||||||
|
"""
|
||||||
|
type = "tls"
|
||||||
|
|
||||||
|
def session(self, server_application):
|
||||||
|
raise NotImplementedError
|
Loading…
Reference in New Issue