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")
Beispiel #2
0
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