Skip to content
This repository has been archived by the owner on Mar 9, 2023. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
… identifier and secret MUST be x-www-form-urlencoded when doing client_secret_basic client authentication.
  • Loading branch information
rohe committed May 3, 2018
1 parent 2a6c4e8 commit c8b60d6
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 8 deletions.
3 changes: 2 additions & 1 deletion src/oic/utils/authn/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging

import six
from future.backports.urllib.parse import quote_plus
from jwkest import Invalid
from jwkest import MissingKey
from jwkest import as_bytes
Expand Down Expand Up @@ -108,7 +109,7 @@ def construct(self, cis, request_args=None, http_args=None, **kwargs):
if "headers" not in http_args:
http_args["headers"] = {}

credentials = "{}:{}".format(user, passwd)
credentials = "{}:{}".format(quote_plus(user), quote_plus(passwd))
authz = base64.urlsafe_b64encode(credentials.encode("utf-8")).decode(
"utf-8")
http_args["headers"]["Authorization"] = "Basic {}".format(authz)
Expand Down
11 changes: 7 additions & 4 deletions src/oic/utils/authn/user.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# coding=utf-8
from future.backports.urllib.parse import unquote
from future.backports.urllib.parse import unquote_plus
from future.backports.urllib.parse import urlencode
from future.backports.urllib.parse import urlsplit
from future.backports.urllib.parse import urlunsplit
from future.moves.urllib.parse import parse_qs

import base64
import logging
import six
import time

import six
from jwkest import as_unicode

from oic.exception import ImproperlyConfigured
from oic.exception import PyoidcError
Expand Down Expand Up @@ -377,8 +378,10 @@ def authenticated_as(self, cookie=None, authorization="", **kwargs):
if authorization.startswith("Basic"):
authorization = authorization[6:]

(user, pwd) = base64.b64decode(authorization).split(":")
user = unquote(user)
_decoded = as_unicode(base64.b64decode(authorization))
(user, pwd) = _decoded.split(":")
user = unquote_plus(user)
pwd = unquote_plus(pwd)
self.verify_password(user, pwd)
return {"uid": user}, time.time()

Expand Down
22 changes: 22 additions & 0 deletions tests/test_authn_user.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import base64

import pytest
from future.backports.urllib.parse import quote_plus

from oic.exception import ImproperlyConfigured
from oic.utils.authn.user import BasicAuthn
from oic.utils.authn.user import SymKeyAuthn


Expand All @@ -15,3 +18,22 @@ def test_symkeyauthn_improperly_configured(provider):
)
expected_msg = "SymKeyAuthn.symkey cannot be an empty value"
assert expected_msg in str(err.value)


def test_basic_authn_authenticate_as():
pwd_database = {
'Diana': 'Piano player',
'NonAscii': '€&+%#@äää'
}
ba = BasicAuthn(None, pwd=pwd_database)

for user, passwd in pwd_database.items():
credentials = "{}:{}".format(quote_plus(user),
quote_plus(passwd))

authz = base64.urlsafe_b64encode(credentials.encode("utf-8")).decode(
"utf-8")
authorization_string = "Basic {}".format(authz)

uid, when = ba.authenticated_as(authorization=authorization_string)
assert uid == {'uid': user}
6 changes: 3 additions & 3 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os

import pytest
from future.backports.urllib.parse import quote_plus
from jwkest import as_bytes
from jwkest import b64e
from jwkest.jwk import SYMKey
Expand Down Expand Up @@ -52,10 +53,9 @@ def test_construct(self, client):

csb = ClientSecretBasic(client)
http_args = csb.construct(cis)

cred = '{}:{}'.format(quote_plus("A"), quote_plus("boarding pass"))
assert http_args == {"headers": {"Authorization": "Basic {}".format(
base64.urlsafe_b64encode("A:boarding pass".encode("utf-8")).decode(
"utf-8"))}}
base64.urlsafe_b64encode(cred.encode("utf-8")).decode("utf-8"))}}

def test_does_not_remove_padding(self):
cis = AccessTokenRequest(code="foo", redirect_uri="http://example.com")
Expand Down

0 comments on commit c8b60d6

Please sign in to comment.