Пример #1
0
def reg_request():
    username = request.form.get('register_username')
    display_name = request.form.get('register_display_name')

    rp_name = 'localhost'
    challenge = util.generate_challenge(32)
    ukey = util.generate_ukey()

    if 'register_ukey' in session:
        del session['register_ukey']
    if 'register_username' in session:
        del session['register_username']
    if 'register_display_name' in session:
        del session['register_display_name']
    if 'challenge' in session:
        del session['challenge']

    session['register_username'] = username
    session['register_display_name'] = display_name
    session['challenge'] = challenge
    session['register_ukey'] = ukey

    make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge, rp_name, RP_ID, ukey, username, display_name,
        'https://example.com')
    # print(make_credential_options)
    # print(make_credential_options.registration_dict)
    return json.jsonify(make_credential_options.registration_dict)
Пример #2
0
def register_start():
    username, password = request.json.get('username'), request.json.get('password')
    if not isinstance(username, str) or not re.match(r"^[a-zA-Z0-9]{1,32}$", username):
        logger.info(f"Register start failed: invalid username {username}")
        return jsonify(status='failure', error='Invalid username, must be an alphanumeric string')
    if not isinstance(password, str) or len(password) < 8:
        logger.info(f"Register start failed: invalid password")
        return jsonify(status='failure', error='Invalid password, must be at least 8 characters')
    logger.info(f"Register started for user {username}")

    challenge = secrets.token_urlsafe(32)
    user_id = secrets.token_urlsafe(20)

    session['challenge'] = challenge
    session['user_id'] = user_id
    session['username'] = username
    session['password_hash'] = generate_password_hash(password)

    make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge=challenge,
        rp_name=RELYING_PARTY_NAME,
        rp_id=RELYING_PARTY_ID,
        user_id=user_id,
        username=username,
        display_name=username,
        icon_url=ICON_URL,
    )
    logger.info(f"Register challenge issued for user {username} with challenge {challenge}")
    return jsonify(status='success', options=make_credential_options.registration_dict)
Пример #3
0
def webauthn_begin_activate(request):
    form = KeyRegistrationForm(request.POST)

    if not form.is_valid():
        return JsonResponse({"errors": form.errors}, status=400)

    username = request.user.get_username()
    display_name = request.user.get_full_name()

    challenge = util.generate_challenge(32)
    ukey = util.generate_ukey()

    request.session["key_name"] = form.cleaned_data["key_name"]
    request.session["challenge"] = challenge
    request.session["register_ukey"] = ukey

    make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge,
        settings.RELYING_PARTY_NAME,
        settings.RELYING_PARTY_ID,
        ukey,
        username,
        display_name,
        settings.WEBAUTHN_ICON_URL,
    )

    return JsonResponse(make_credential_options.registration_dict)
Пример #4
0
def register_challenge():
    schema = RegisterChallengeSchema()
    user = schema.load(request.get_json())
    challenge = random_string()

    token = guard.encode_jwt_token(
        user,
        is_registration=True,
        email=user.email,
        name=user.name,
        challenge=challenge,
    )

    options = webauthn.WebAuthnMakeCredentialOptions(
        challenge=challenge,
        rp_name=app.config["WEBAUTHN_RP_NAME"],
        rp_id=app.config["WEBAUTHN_RP_ID"],
        user_id=user.id.hex,
        username=user.email,
        display_name=user.name,
        icon_url=app.config["WEBAUTHN_ICON_URL"],
        attestation="none",
    ).registration_dict

    return {
        "token": token,
        "options": options,
    }
Пример #5
0
def webauthn_begin_activate(request):
    print("webauthn_begin_activate")
    # username = request.POST.get('username')
    global username
    username = request.POST.get('register_username', '')
    display_name = request.POST.get('register_display_username')
    print(username)
    rp_name = "localhost"
    challenge = generate_challenge(32)
    ukey = generate_ukey()
    if 'register_ukey' in request.session:
        del request.session['register_ukey']
    if 'register_username' in request.session:
        del request.session['register_username']
    if 'register_display_name' in request.session:
        del request.session['register_display_name']
    if 'challenge' in request.session:
        del request.session['challenge']
    request.session['register_username'] = username
    request.session['register_display_name'] = display_name
    request.session['challenge'] = challenge
    request.session['register_ukey'] = ukey

    make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge, rp_name, RP_ID, ukey, username, display_name,
        'https://chendin.com')
    temp = make_credential_options.registration_dict
    # temp['attestation'] = 'direct'
    return JsonResponse(temp)
Пример #6
0
def webauthn_begin_activate(election):
    email = session['email']
    name = session['name']

    if not len(email):
        return make_response(jsonify({'fail': 'Invalid email.'}), 401)
    if not len(name):
        return make_response(jsonify({'fail': 'Invalid  name.'}), 401)

    if Authority.query.filter(Election.name == election,
                              Authority.email == email).first():
        return make_response(jsonify({'fail': 'User already exists.'}), 401)

    if 'register_ukey' in session:
        del session['register_ukey']
    if 'register_username' in session:
        del session['register_username']
    if 'register_display_name' in session:
        del session['register_display_name']
    if 'challenge' in session:
        del session['challenge']

    http = request.url.split("://")
    origin = f"{http[0]}://{election}.{ORIGIN}"
    challenge = generate_challenge(32)
    ukey = generate_ukey()

    session['challenge'] = challenge
    session['register_ukey'] = ukey

    make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge, RP_ID, RP_ID, ukey, email, name, origin)

    return jsonify(make_credential_options.registration_dict)
Пример #7
0
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data()
        ctx['device'] = self.device

        if 'webauthn_register_ukey' in self.request.session:
            del self.request.session['webauthn_register_ukey']
        if 'webauthn_challenge' in self.request.session:
            del self.request.session['webauthn_challenge']

        challenge = generate_challenge(32)
        ukey = generate_ukey()

        self.request.session['webauthn_challenge'] = challenge
        self.request.session['webauthn_register_ukey'] = ukey

        make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
            challenge,
            urlparse(settings.SITE_URL).netloc,
            urlparse(settings.SITE_URL).netloc,
            ukey,
            self.request.user.email,
            str(self.request.user),
            settings.SITE_URL
        )
        ctx['jsondata'] = json.dumps(make_credential_options.registration_dict)

        return ctx
Пример #8
0
 def begin_register(self, request):
     challenge = generate_challenge()
     request.session['challenge'] = challenge
     ukey = base64.urlsafe_b64encode(str(request.user.id).encode('utf-8'))
     make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
         challenge, self._get_rp_name(request), self._get_rp_id(request),
         ukey, request.user.username, request.user.username,
         self._get_origin(request))
     return make_credential_options.registration_dict
Пример #9
0
 def setUp(self):
     self.options = webauthn.WebAuthnMakeCredentialOptions(
         REGISTRATION_CHALLENGE,
         RP_NAME,
         RP_ID,
         USER_ID,
         USER_NAME,
         USER_DISPLAY_NAME,
         ICON_URL
     )
Пример #10
0
def get_credential_options(user, *, challenge, rp_name, rp_id, icon_url):
    """
    Returns a dictionary of options for credential creation
    on the client side.
    """
    options = pywebauthn.WebAuthnMakeCredentialOptions(challenge, rp_name,
                                                       rp_id, str(user.id),
                                                       user.username,
                                                       user.name, icon_url)

    return options.registration_dict
Пример #11
0
def get_credential_options(user, *, challenge, rp_name, rp_id):
    """
    Returns a dictionary of options for credential creation
    on the client side.
    """
    options = pywebauthn.WebAuthnMakeCredentialOptions(
        challenge,
        rp_name,
        rp_id,
        str(user.id),
        user.username,
        user.name,
        None,
        user_verification="discouraged",
    )

    return options.registration_dict
Пример #12
0
def webauthn_registration_start():
    """Starts the webauthn registration process by sending the user a random challenge"""

    # MakeCredentialOptions
    email = request.form['email']

    # Verify that email and display name are acceptable
    # TODO: improve error screen (likely using flashing)
    if not validate_email(email):
        flash('Invalid email', 'error')
        return make_response(jsonify({'redirect': url_for('register')}), 401)

    display_name = get_display_name(email)

    # Ensure the user's email isn't already in use (TODO: refactor into a function for
    # both registration stages)
    if User.query.filter_by(email=email).first():
        flash('Email address is already in use', 'error')
        return make_response(jsonify({'redirect': url_for('register')}), 401)

    # We strip the saved challenge of padding, so that we can do a byte
    # comparison on the URL-safe-without-padding challenge we get back
    # from the browser.
    # We will still pass the padded version down to the browser so that the JS
    # can decode the challenge into binary without too much trouble.
    challenge = secrets.token_urlsafe(32)
    ukey = secrets.token_urlsafe(20)
    session['registration'] = {
        'email': email,
        'display_name': display_name,
        'challenge': challenge.rstrip('='),
        'ukey': ukey,
    }

    make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge=challenge,
        rp_name=RP_NAME,
        rp_id=RP_ID,
        user_id=ukey,
        username=email,
        display_name=display_name,
        icon_url='https://example.com',
    )

    return jsonify(make_credential_options.registration_dict)
Пример #13
0
def webauthn_begin_register():
    # MakeCredentialOptions
    username = request.form.get('register_username')
    display_name = request.form.get('register_display_name')
    password = request.form.get('register_password')

    if not util.validate_username(username):
        return make_response(jsonify({'fail': 'Invalid username.'}), 401)
    if not util.validate_display_name(display_name):
        return make_response(jsonify({'fail': 'Invalid display name.'}), 401)
    
    if auth.isRegistered(username):
        return make_response(jsonify({'fail': 'User already exists.'}), 401)

    #clear session variables prior to starting a new registration
    session.pop('register_ukey', None)
    session.pop('register_username', None)
    session.pop('register_display_name', None)
    session.pop('register_password', None)
    session.pop('challenge', None)

    session['register_username'] = username
    session['register_display_name'] = display_name

    # TODO: I am not sure if this is safe to do?!?!?
    session['register_password'] = password

    challenge = util.generate_challenge(32)
    ukey = util.generate_ukey()

    # We strip the saved challenge of padding, so that we can do a byte
    # comparison on the URL-safe-without-padding challenge we get back
    # from the browser.
    # We will still pass the padded version down to the browser so that the JS
    # can decode the challenge into binary without too much trouble.
    session['challenge'] = challenge.rstrip('=')
    session['register_ukey'] = ukey
    
    make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge, RP_NAME, RP_ID, ukey, username, display_name,
        ORIGIN, attestation='none')
    
    return jsonify(make_credential_options.registration_dict)
Пример #14
0
 def get(self, request, *args, **kwargs):
     challenge = os.urandom(32)
     request.session['webauthn_attest'] = webauthn_encode(challenge)
     data = webauthn.WebAuthnMakeCredentialOptions(
         challenge=challenge,
         rp_id=settings.WEBAUTHN_RP_ID,
         rp_name=settings.SITE_NAME,
         user_id=request.profile.webauthn_id,
         username=request.user.username,
         display_name=request.user.username,
         user_verification='discouraged',
         icon_url=gravatar(request.user.email),
         attestation='none',
     ).registration_dict
     data['excludeCredentials'] = [{
         'type': 'public-key',
         'id': {
             '_bytes': credential.cred_id
         },
     } for credential in request.profile.webauthn_credentials.all()]
     return JsonResponse(data, encoder=WebAuthnJSONEncoder)
Пример #15
0
def register_start():
    username = request.json.get('username')
    assert isinstance(username, str) and re.match(r"^[a-zA-Z0-9]{1,32}$", username), username

    challenge = secrets.token_urlsafe(32)
    user_id = secrets.token_urlsafe(20)

    session['challenge'] = challenge
    session['user_id'] = user_id
    session['username'] = username

    make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge=challenge,
        rp_name=RELYING_PARTY_NAME,
        rp_id=RELYING_PARTY_ID,
        user_id=user_id,
        username=username,
        display_name=username,
        icon_url=ICON_URL,
    )
    return jsonify(status='success', options=make_credential_options.registration_dict)
def register_webauthn_user(request):
    username = request.POST["username"]
    user_display_name = request.POST["user_display_name"]
    current_site_details = get_current_site(request)
    webauthn_challenge = token_urlsafe_without_stripping(32)
    webauthn_ukey = token_urlsafe_without_stripping(20)
    request.session["challenge"] = webauthn_challenge.rstrip(
        '=')  # For byte comparison,strip= before saving in session
    request.session["webauthn_ukey"] = webauthn_ukey
    request.session["username"] = username
    request.session["user_display_name"] = user_display_name
    return JsonResponse(
        webauthn.WebAuthnMakeCredentialOptions(
            challenge=webauthn_challenge,
            rp_name=current_site_details.name.split(":")[0],
            rp_id=current_site_details.domain.split(":")[0],
            user_id=webauthn_ukey,
            username=username,
            display_name=user_display_name,
            icon_url=
            "https://rajeevkr.me/assets/img/portfolio/IMG_20180302_232843.jpg",
            # attestation='indirect'
        ).registration_dict)
Пример #17
0
def add_authenticator_challenge():
    user = current_user()
    challenge = random_string()

    token = guard.encode_jwt_token(
        user, is_add_authenticator=True, challenge=challenge,
    )

    options = webauthn.WebAuthnMakeCredentialOptions(
        challenge=challenge,
        rp_name=app.config["WEBAUTHN_RP_NAME"],
        rp_id=app.config["WEBAUTHN_RP_ID"],
        user_id=user.id.hex,
        username=user.email,
        display_name=user.name,
        icon_url=app.config["WEBAUTHN_ICON_URL"],
        attestation="none",
    ).registration_dict

    return {
        "token": token,
        "options": options,
    }
Пример #18
0
def webauthn_begin_activate():
    # MakeCredentialOptions
    username = request.form.get('register_username')
    display_name = request.form.get('register_display_name')

    if not util.validate_username(username):
        return make_response(jsonify({'fail': 'Invalid username.'}), 401)
    if not util.validate_display_name(display_name):
        return make_response(jsonify({'fail': 'Invalid display name.'}), 401)

    if User.query.filter_by(username=username).first():
        return make_response(jsonify({'fail': 'User already exists.'}), 401)

    if 'register_ukey' in session:
        del session['register_ukey']
    if 'register_username' in session:
        del session['register_username']
    if 'register_display_name' in session:
        del session['register_display_name']
    if 'challenge' in session:
        del session['challenge']

    session['register_username'] = username
    session['register_display_name'] = display_name

    rp_name = 'localhost'
    challenge = util.generate_challenge(32)
    ukey = util.generate_ukey()

    session['challenge'] = challenge
    session['register_ukey'] = ukey

    make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge, rp_name, RP_ID, ukey, username, display_name,
        'https://example.com')

    return jsonify(make_credential_options.registration_dict)
Пример #19
0
def webauthn_begin_activate():
    jsonData = request.get_json()
    name = jsonData['name']
    surname = jsonData['surname']
    email = jsonData['email']
    username = email
    display_name = name + " " + surname
    challenge = util.generate_challenge(32)
    id = util.generate_ukey()
    '''
     PublicKeyCredentialCreationOptions
     rp-> Relying Party: It's the server where you want to authenticate.
            RP_NAME: name
            RP_ID: The RP ID must be equal to the origin's effective domain, or a registrable domain suffix of
                   the origin's effective domain.
                   The origin's scheme must be https.
                   The origin's port is unrestricted.
     user information->
            Information about the user registering
            Helps to choose from multiple credentials.
            username: it is a human-palatable identifier for a user account.
                    It is intended only for display, i.e., aiding the user in determining
                    the difference between user accounts with similar displayNames.
                    For example, "alexm", "*****@*****.**" or "+14255551234".
            display_name: A human-palatable name for the user account, intended only for display. For example, "Alex P. Müller" or "田中 倫".
                         The Relying Party SHOULD let the user choose this, and SHOULD NOT restrict the choice more than necessary.
            id: The user handle of the user account entity.
                A user handle is an opaque byte sequence with a maximum size of 64 bytes,
                and is not meant to be displayed to the user.
    '''
    make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge, RP_NAME, RP_ID, id, username, display_name,
        'http://localhost')
    challenge = challenge.rstrip("=")
    insert = database.insert_db("insert into PublicKeyCredentialCreationOptions VALUES (?,?,?,?,?,?)",[RP_NAME, RP_ID,id,display_name,username,challenge])
    return jsonify(make_credential_options.registration_dict)
Пример #20
0
def fido_setup():
    if current_user.fido_uuid is not None:
        fidos = Fido.filter_by(uuid=current_user.fido_uuid).all()
    else:
        fidos = []

    fido_token_form = FidoTokenForm()

    # Handling POST requests
    if fido_token_form.validate_on_submit():
        try:
            sk_assertion = json.loads(fido_token_form.sk_assertion.data)
        except Exception:
            flash("Key registration failed. Error: Invalid Payload", "warning")
            return redirect(url_for("dashboard.index"))

        fido_uuid = session["fido_uuid"]
        challenge = session["fido_challenge"]

        fido_reg_response = webauthn.WebAuthnRegistrationResponse(
            RP_ID,
            URL,
            sk_assertion,
            challenge,
            trusted_attestation_cert_required=False,
            none_attestation_permitted=True,
        )

        try:
            fido_credential = fido_reg_response.verify()
        except Exception as e:
            LOG.warning(
                f"An error occurred in WebAuthn registration process: {e}")
            flash("Key registration failed.", "warning")
            return redirect(url_for("dashboard.index"))

        if current_user.fido_uuid is None:
            current_user.fido_uuid = fido_uuid
            db.session.flush()

        Fido.create(
            credential_id=str(fido_credential.credential_id, "utf-8"),
            uuid=fido_uuid,
            public_key=str(fido_credential.public_key, "utf-8"),
            sign_count=fido_credential.sign_count,
            name=fido_token_form.key_name.data,
        )
        db.session.commit()

        LOG.d(
            f"credential_id={str(fido_credential.credential_id, 'utf-8')} added for {fido_uuid}"
        )

        flash("Security key has been activated", "success")
        if not RecoveryCode.query.filter_by(user_id=current_user.id).all():
            return redirect(url_for("dashboard.recovery_code_route"))
        else:
            return redirect(url_for("dashboard.fido_manage"))

    # Prepare information for key registration process
    fido_uuid = (str(uuid.uuid4())
                 if current_user.fido_uuid is None else current_user.fido_uuid)
    challenge = secrets.token_urlsafe(32)

    credential_create_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge,
        "SimpleLogin",
        RP_ID,
        fido_uuid,
        current_user.email,
        current_user.name if current_user.name else current_user.email,
        False,
        attestation="none",
        user_verification="discouraged",
    )

    # Don't think this one should be used, but it's not configurable by arguments
    # https://www.w3.org/TR/webauthn/#sctn-location-extension
    registration_dict = credential_create_options.registration_dict
    del registration_dict["extensions"]["webauthn.loc"]

    # Prevent user from adding duplicated keys
    for fido in fidos:
        registration_dict["excludeCredentials"].append({
            "type":
            "public-key",
            "id":
            fido.credential_id,
            "transports": ["usb", "nfc", "ble", "internal"],
        })

    session["fido_uuid"] = fido_uuid
    session["fido_challenge"] = challenge.rstrip("=")

    return render_template(
        "dashboard/fido_setup.html",
        fido_token_form=fido_token_form,
        credential_create_options=registration_dict,
    )
Пример #21
0
def fido_setup():
    if current_user.fido_enabled():
        flash("You have already registered your security key", "warning")
        return redirect(url_for("dashboard.index"))

    if not current_user.can_use_fido:
        flash(
            "This feature is currently in invitation-only beta. Please send us an email if you want to try",
            "warning",
        )
        return redirect(url_for("dashboard.index"))

    fido_token_form = FidoTokenForm()

    # Handling POST requests
    if fido_token_form.validate_on_submit():
        try:
            sk_assertion = json.loads(fido_token_form.sk_assertion.data)
        except Exception as e:
            flash("Key registration failed. Error: Invalid Payload", "warning")
            return redirect(url_for("dashboard.index"))

        fido_uuid = session["fido_uuid"]
        challenge = session["fido_challenge"]

        fido_reg_response = webauthn.WebAuthnRegistrationResponse(
            RP_ID,
            URL,
            sk_assertion,
            challenge,
            trusted_attestation_cert_required=False,
            none_attestation_permitted=True,
        )

        try:
            fido_credential = fido_reg_response.verify()
        except Exception as e:
            LOG.error(
                f"An error occurred in WebAuthn registration process: {e}")
            flash("Key registration failed.", "warning")
            return redirect(url_for("dashboard.index"))

        current_user.fido_pk = str(fido_credential.public_key, "utf-8")
        current_user.fido_uuid = fido_uuid
        current_user.fido_sign_count = fido_credential.sign_count
        current_user.fido_credential_id = str(fido_credential.credential_id,
                                              "utf-8")
        db.session.commit()

        flash("Security key has been activated", "success")

        return redirect(url_for("dashboard.index"))

    # Prepare information for key registration process
    fido_uuid = str(uuid.uuid4())
    challenge = secrets.token_urlsafe(32)

    credential_create_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge,
        "SimpleLogin",
        RP_ID,
        fido_uuid,
        current_user.email,
        current_user.name if current_user.name else current_user.email,
        False,
        attestation="none",
        user_verification="discouraged",
    )

    # Don't think this one should be used, but it's not configurable by arguments
    # https://www.w3.org/TR/webauthn/#sctn-location-extension
    registration_dict = credential_create_options.registration_dict
    del registration_dict["extensions"]["webauthn.loc"]

    session["fido_uuid"] = fido_uuid
    session["fido_challenge"] = challenge.rstrip("=")

    return render_template(
        "dashboard/fido_setup.html",
        fido_token_form=fido_token_form,
        credential_create_options=registration_dict,
    )
Пример #22
0
 def setUp(self):
     self.options = webauthn.WebAuthnMakeCredentialOptions(
         self.REGISTRATION_CHALLENGE, self.RP_NAME, self.RP_ID,
         self.USER_ID, self.USER_NAME, self.USER_DISPLAY_NAME,
         self.ICON_URL, self.EXCLUDE_CREDENTIAL)