def associate_by_email_if_saml(auth_entry, backend, details, user, strategy, *args, **kwargs): """ This pipeline step associates the current social auth with the user with the same email address in the database. It defers to the social library's associate_by_email implementation, which verifies that only a single database user is associated with the email. This association is done ONLY if the user entered the pipeline belongs to SAML provider. """ def get_user(): """ This is the helper method to get the user from system by matching email. """ user_details = {'email': details.get('email')} if details else None return get_user_from_email(user_details or {}) def associate_by_email_if_enterprise_user(): """ If the learner arriving via SAML is already linked to the enterprise customer linked to the same IdP, they should not be prompted for their edX password. """ try: enterprise_customer_user = is_enterprise_customer_user( current_provider.provider_id, current_user) logger.info( '[Multiple_SSO_SAML_Accounts_Association_to_User] Enterprise user verification:' 'User Email: {email}, User ID: {user_id}, Provider ID: {provider_id},' ' is_enterprise_customer_user: {enterprise_customer_user}'. format( email=current_user.email, user_id=current_user.id, provider_id=current_provider.provider_id, enterprise_customer_user=enterprise_customer_user, )) if enterprise_customer_user: # this is python social auth pipeline default method to automatically associate social accounts # if the email already matches a user account. association_response, user_is_active = get_associated_user_by_email_response( backend, details, user, *args, **kwargs) if not user_is_active: logger.info( '[Multiple_SSO_SAML_Accounts_Association_to_User] User association account is not' ' active: User Email: {email}, User ID: {user_id}, Provider ID: {provider_id},' ' is_enterprise_customer_user: {enterprise_customer_user}' .format( email=current_user.email, user_id=current_user.id, provider_id=current_provider.provider_id, enterprise_customer_user=enterprise_customer_user)) return None return association_response except Exception as ex: # pylint: disable=broad-except logger.exception( '[Multiple_SSO_SAML_Accounts_Association_to_User] Error in' ' saml multiple accounts association: User ID: %s, User Email: %s:,' 'Provider ID: %s, Exception: %s', current_user.id, current_user.email, current_provider.provider_id, ex) saml_provider, current_provider = is_saml_provider( strategy.request.backend.name, kwargs) if saml_provider: # get the user by matching email if the pipeline user is not available. current_user = user if user else get_user() # Verify that the user linked to enterprise customer of current identity provider and an active user associate_response = associate_by_email_if_enterprise_user( ) if current_user else None if associate_response: return associate_response
def associate_by_email_if_saml(auth_entry, backend, details, user, strategy, *args, **kwargs): """ This pipeline step associates the current social auth with the user with the same email address in the database. It defers to the social library's associate_by_email implementation, which verifies that only a single database user is associated with the email. This association is done ONLY if the user entered the pipeline belongs to SAML provider. """ def get_user(): """ This is the helper method to get the user from system by matching email. """ user_details = {'email': details.get('email')} if details else None return get_user_from_email(user_details or {}) def associate_by_email_if_enterprise_user(): """ If the learner arriving via SAML is already linked to the enterprise customer linked to the same IdP, they should not be prompted for their edX password. """ try: enterprise_customer_user = is_enterprise_customer_user( current_provider.provider_id, current_user) logger.info( u'[Multiple_SSO_SAML_Accounts_Association_to_User] Enterprise user verification:' u'Email: {email}, user_id: {user_id}, Provider: {provider},' u' enterprise_customer_user: {enterprise_customer_user}'. format( email=current_user.email, user_id=current_user.id, provider=current_provider.provider_id, enterprise_customer_user=enterprise_customer_user, )) if enterprise_customer_user: # this is python social auth pipeline default method to automatically associate social accounts # if the email already matches a user account. association_response = associate_by_email( backend, details, user, *args, **kwargs) if (association_response and association_response.get('user') and association_response['user'].is_active): # Only return the user matched by email if their email has been activated. # Otherwise, an illegitimate user can create an account with another user's # email address and the legitimate user would now login to the illegitimate # account. return association_response elif (association_response and association_response.get('user') and not association_response['user'].is_active): logger.info( u'[Multiple_SSO_SAML_Accounts_Association_to_User] User association account is not' u' active: Email: {email}, user_id: {user_id}, Provider: {provider},' u' enterprise_customer_user: {enterprise_customer_user}' .format( email=current_user.email, user_id=current_user.id, provider=current_provider.provider_id, enterprise_customer_user=enterprise_customer_user)) return None except Exception as ex: # pylint: disable=broad-except logger.exception( '[Multiple_SSO_SAML_Accounts_Association_to_User] Error in' ' saml multiple accounts association: %s:, %s:', current_user.id, ex) # this is waffle switch to enable and disable this functionality from admin panel. if is_multiple_sso_accounts_association_to_saml_user_enabled(): saml_provider, current_provider = is_saml_provider( strategy.request.backend.name, kwargs) if saml_provider: # get the user by matching email if the pipeline user is not available. current_user = user if user else get_user() # Verify that the user linked to enterprise customer of current identity provider and an active user associate_response = associate_by_email_if_enterprise_user( ) if current_user else None if associate_response: return associate_response