class APIClient: def __init__(self, connection, configuration): auth = configuration.get('auth') self.client = OneLoginClient(auth.get('clientId'), auth.get('clientSecret'), connection['region']) def generate_token(self): """To generate the Token""" self.client.get_access_token() return self.response_handler() def run_search(self, query_expr, range_end=None): """get the response from onelogin endpoints :param quary_expr: dict, filter parameters :param range_end: int,length value :return: response, json object""" token = self.client.get_access_token() events = [] if token and self.client.error is None: events = self.client.get_events(query_expr, max_results=range_end) return self.response_handler(events) def response_handler(self, data=None): if data is None: data = [] response = dict() if self.client.error: response["code"] = int(self.client.error) if self.client.error is None: response.update({"code": 200, "data": data}) elif self.client.error == 500 and "local variable 'data' referenced before assignment" in self.client.error_description: response.update({"code": 200, "data": []}) else: response["message"] = self.client.error_description return response
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