def one_tap_login(request): received_json_data = json.loads(request.body) credential = received_json_data['credential'] decoded = jwt.decode(credential, verify=False) user_data = { "name": decoded['name'], "email": decoded['email'], "given_name": decoded['given_name'], "family_name": decoded['family_name'] } json_user_data = json.dumps(user_data) request.session['user_data'] = json_user_data # run this in command shell: # python manage.py migrate client = OneLoginClient( mysecrets.ONELOGIN_CLIENT_ID, mysecrets.ONELOGIN_CLIENT_SECRET, 'us' ) # 1. Make sure the user you want to create does not exist yet users = client.get_users({ "email": decoded["email"] }) # 2. Create the new user (explain the most interesting user parameters) if len(users) == 0: new_user_params = { "email": decoded["email"], "firstname": decoded["name"], "lastname": decoded["given_name"], "username": decoded["family_name"] } created_user = client.create_user(new_user_params) if created_user is not None: # 3. Assign the Default role to the user roles = client.get_roles({ "name": "Default" }) if len(roles) == 1: role_ids = [ roles[0].id ] client.assign_role_to_user(created_user.id, role_ids) # 4. Set the user state USER_STATE_APPROVED = 1 client.set_state_to_user(created_user.id, USER_STATE_APPROVED) return HttpResponse(json_user_data, content_type="application/json")
class OneLogin: def __init__(self): CLIENT_ID = os.environ["ONELOGIN_CLIENT_ID"] CLIENT_SECRET = os.environ["ONELOGIN_CLIENT_SECRET"] REGION = os.environ.get("ONELOGIN_REGION", "US").upper() self.client = OneLoginClient(CLIENT_ID, CLIENT_SECRET, REGION) def get_group_members(self, group_name=None): """ This is technically not named well, since we're getting users assigned to a role, but because of the existing framework, the matching the function name keeps it reusable :param group_name: :return: """ member_list = [] role = self.client.get_roles(query_parameters={"name": group_name}) users = self.client.get_users(query_parameters={"role_id": role[0].id}) for user in users: member_list.append({"username": user.username, "email": user.email}) return member_list
def pam_sm_authenticate(pamh, _flags, _argv): ''' Authenticates a user via onelogin email/username and OTP ''' # Load config file and build access token try: config_dpath = os.path.dirname(os.path.realpath(__file__)) config_fpath = os.path.join(config_dpath, 'onepam.json') config_fd = open(config_fpath, 'r') config = config_fd.read() config_fd.close() config = json.loads(config) except Exception as error: logit('Error loading configuration: %s' % error) return pamh.PAM_AUTH_ERR # Create a client to OneLogin with the config details client = OneLoginClient(config['client_id'], config['client_secret'], config['region']) if not client.get_access_token(): logit('Error authenticating with onelogin') return pamh.PAM_AUTH_ERR # Prompt user for needed information try: # Unix user (aka, the onelogin role - usually passed via ssh, but may need to prompt) rolename = pamh.get_user(None) if rolename is None: return pamh.PAM_USER_UNKNOWN # OneLogin email/user email_or_user = pamh.conversation( pamh.Message(pamh.PAM_PROMPT_ECHO_ON, 'OneLogin email or user: '******'OneLogin password: '******'*') >= 0: logit('Invalid user "%s"' % email_or_user) return pamh.PAM_AUTH_ERR # Build uniform request object from config file uniform_timer = UniformTimer(config['request_duration_secs']) # Make all email/user/checks have a uniform duration (start) uniform_timer.start() # Query emails emails = client.get_users({'email': email_or_user}) if emails is None: logit('Error querying email "%s"' % email_or_user) return pamh.PAM_AUTH_ERR # Query users users = client.get_users({'username': email_or_user}) if users is None: logit('Error querying user "%s"' % email_or_user) return pamh.PAM_AUTH_ERR # Search emails first then users user = None for entry in emails: if entry.email == email_or_user: user = entry break if not user: for entry in users: if entry.username == email_or_user: user = entry break # Make all email/user/checks have a uniform duration (finish) uniform_timer.finish() # Check password (uncomment to add password auth) # uniform_timer.start() # token = client.create_session_login_token({'username_or_email': email_or_user, # 'password': password, # 'subdomain': config['subdomain']}) # if token is None: # logit('Invalid username or password "%s"' % email_or_user) # user = None # uniform_timer.finish() # Valid user - query otp factors uniform_timer.start() device = None if user: factors = client.get_enrolled_factors(user.id) # Error querying devices - log and set user to None if factors is None: logit('Error querying enrolled factors for user "%s"' % email_or_user) user = None # Find a factor for user (default is preferred, will use first listed otherwise) else: for factor in factors: # Only care about usable factors if not factor.active: continue # Device is the default device - set and break if factor.default: device = factor break # Device isn't default, but some device is better than no device if device is None: device = factor else: logit('Invalid email/user "%s"' % email_or_user) uniform_timer.finish() # User has a valid otp factor - activate it uniform_timer.start() state_token = None if user is not None and device is not None: # Grab state token state_token = device.state_token # Only trigger if device needs it if device.needs_trigger: activation = client.activate_factor(user.id, device.id) if not activation: logit('Error activating factor id %d for user "%s"' % (device.id, email_or_user)) else: state_token = activation.state_token # No active/default factor - log and set user to None else: logit('No valid otp factor found for user "%s"' % email_or_user) uniform_timer.finish() # Prompt for otp try: otp_token = pamh.conversation( pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, 'OTP: ')).resp if not otp_token: otp_token = None except pamh.exception as error: return error.pam_result # Verify otp uniform_timer.start() result = False if user is not None and device is not None: result = client.verify_factor(user.id, device.id, otp_token=otp_token, state_token=state_token) uniform_timer.finish() # Error verifying otp - log if result is None: logit('Error verifying factor id %d for user "%s"' % (device.id, email_or_user)) return pamh.PAM_AUTH_ERR # Invalid otp - log if not result: logit('Invalid otp auth for user "%s"' % email_or_user) return pamh.PAM_AUTH_ERR # Check if user is authorized to login to provided role if config['user_roles'].get(rolename, None) not in user.get_role_ids(): logit('User "%s" is not authorized to login as "%s"' % (email_or_user, rolename)) return pamh.PAM_AUTH_ERR # Auth'd login return pamh.PAM_SUCCESS