示例#1
0
文件: mfa.py 项目: SURFscz/SBS
def _do_verify_2fa(user: User, secret):
    data = current_request.get_json()
    totp_value = data["totp"]
    totp = pyotp.TOTP(secret)
    if totp.verify(totp_value, valid_window=1):
        if not user.second_factor_auth:
            user.second_factor_auth = secret
        user.last_login_date = datetime.datetime.now()
        user = db.session.merge(user)
        db.session.commit()
        store_user_in_session(user, True, user.has_agreed_with_aup())
        return True
    else:
        return False
示例#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)