Esempio n. 1
0
def login_user():
    if not os.environ.get("ALLOW_MOCK_USER_API", None):
        raise Forbidden()

    data = current_request.get_json()
    sub = data["sub"]  # oidc sub maps to sbs uid - see user_claims
    user = User.query.filter(User.uid == sub).first() or User(created_by="system", updated_by="system")

    add_user_claims(data, sub, user, replace_none_values=False)
    db.session.merge(user)

    res = {"admin": is_admin_user(user), "guest": False, "confirmed_admin": user.confirmed_super_user}
    session_data = {
        "id": user.id,
        "uid": user.uid,
        "name": user.name,
        "email": user.email,
        "user_accepted_aup": user.has_agreed_with_aup(),
        "second_factor_confirmed": True
    }
    session["user"] = {**session_data, **res}
    return None, 201
Esempio n. 2
0
def resume_session():
    logger = ctx_logger("oidc")

    cfg = current_app.app_config
    oidc_config = cfg.oidc
    code = query_param("code", required=False, default=None)
    if not code:
        # This means that we are not in the redirect callback, but at the redirect from eduTeams
        logger.debug("Redirect to login in resume-session to start OIDC flow")
        authorization_endpoint = _get_authorization_url()
        return redirect(authorization_endpoint)

    scopes = " ".join(oidc_config.scopes)
    payload = {
        "code": code,
        "grant_type": "authorization_code",
        "scope": scopes,
        "redirect_uri": oidc_config.redirect_uri
    }
    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
        "Cache-Control": "no-cache",
        "Accept": "application/json, application/json;charset=UTF-8"
    }
    response = requests.post(oidc_config.token_endpoint, data=urllib.parse.urlencode(payload),
                             headers=headers, auth=(oidc_config.client_id, oidc_config.client_secret))
    if response.status_code != 200:
        return _redirect_with_error(logger, f"Server error: Token endpoint error (http {response.status_code}")

    token_json = response.json()
    access_token = token_json["access_token"]

    headers = {
        "Accept": "application/json, application/json;charset=UTF-8",
        "Authorization": f"Bearer {access_token}"
    }

    response = requests.get(oidc_config.userinfo_endpoint, headers=headers)
    if response.status_code != 200:
        return _redirect_with_error(logger, f"Server error: User info endpoint error (http {response.status_code}")

    logger = ctx_logger("user")
    user_info_json = response.json()

    logger.debug(f"Userinfo endpoint results {user_info_json}")

    uid = user_info_json["sub"]
    user = User.query.filter(User.uid == uid).first()
    if not user:
        user = User(uid=uid, created_by="system", updated_by="system")
        add_user_claims(user_info_json, uid, user)

        # last_login_date is set later in this method
        user.last_accessed_date = datetime.datetime.now()
        logger.info(f"Provisioning new user {user.uid}")
    else:
        logger.info(f"Updating user {user.uid} with new claims / updated at")
        add_user_claims(user_info_json, uid, user)

    encoded_id_token = token_json["id_token"]
    id_token = decode_jwt_token(encoded_id_token)

    no_mfa_required = not oidc_config.second_factor_authentication_required
    idp_mfa = id_token.get("acr") == ACR_VALUES

    idp_allowed = mfa_idp_allowed(user, user.schac_home_organisation, None)

    second_factor_confirmed = no_mfa_required or idp_mfa or idp_allowed
    if second_factor_confirmed:
        user.last_login_date = datetime.datetime.now()

    user = db.session.merge(user)
    db.session.commit()

    user_accepted_aup = user.has_agreed_with_aup()
    store_user_in_session(user, second_factor_confirmed, user_accepted_aup)

    if not user_accepted_aup:
        location = f"{cfg.base_url}/aup"
    elif not second_factor_confirmed:
        location = f"{cfg.base_url}/2fa"
    else:
        location = session.get("original_destination", cfg.base_url)

    return redirect(location)
Esempio n. 3
0
 def test_add_user_claims_user_name(self):
     user = User()
     add_user_claims({"given_name": "John", "family_name": "Doe"}, "urn:johny", user)
     self.assertEqual("jdoe", user.username)
Esempio n. 4
0
 def test_bugfix_empty_user_claims_affiliation_list(self):
     user = User()
     add_user_claims({"voperson_external_id": []}, "urn:johny", user)
     self.assertIsNone(user.schac_home_organisation)
Esempio n. 5
0
 def test_user_claims_schac_home_org(self):
     user = User()
     user_info_json_str = self.read_file("user_info.json")
     user_info_json = json.loads(user_info_json_str)
     add_user_claims(user_info_json, "urn:new_user", user)
     self.assertEqual("rug", user.schac_home_organisation)
Esempio n. 6
0
 def test_add_user_claims_empty_entitlements(self):
     user = User()
     add_user_claims({"eduperson_entitlement": []}, "urn:johny", user)
     self.assertIsNone(user.entitlement)
Esempio n. 7
0
 def test_add_user_claims_no_voperson_external_id(self):
     user = User()
     add_user_claims({}, "urn:johny", user)
     self.assertIsNone(user.schac_home_organisation)
Esempio n. 8
0
 def test_add_user_claims_affiliation_defensive(self):
     user = User()
     add_user_claims({"voperson_external_id": "university"}, "urn:johny", user)
     self.assertIsNone(user.schac_home_organisation)
Esempio n. 9
0
 def test_add_user_claims_affiliation_list(self):
     user = User()
     add_user_claims({"voperson_external_id": ["*****@*****.**"]}, "urn:johny", user)
     self.assertEqual("sub.uni.org", user.schac_home_organisation)
Esempio n. 10
0
 def test_add_user_claims_affiliation(self):
     user = User()
     add_user_claims({"voperson_external_id": "teacher@university"}, "urn:johny", user)
     self.assertEqual("university", user.schac_home_organisation)
Esempio n. 11
0
 def test_add_user_claims(self):
     user = User()
     add_user_claims({}, "urn:johny", user)
     self.assertEqual("urn:johny", user.name)