Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Commit 6dffa5f

Browse files
committed
Make sure characters in the error text are from the proper set.
Added two more message classes related to two IETF OAuthh2 drafts.
1 parent 109f86a commit 6dffa5f

File tree

1 file changed

+89
-14
lines changed

1 file changed

+89
-14
lines changed

src/oidcmsg/oauth2/__init__.py

Lines changed: 89 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import inspect
22
import logging
3+
import string
34
import sys
45

5-
6+
from oidcmsg import verified_claim_name
7+
from oidcmsg.exception import MissingAttribute
68
from oidcmsg.exception import VerificationError
79
from oidcmsg.message import Message
810
from oidcmsg.message import OPTIONAL_LIST_OF_SP_SEP_STRINGS
@@ -24,13 +26,25 @@ def is_error_message(msg):
2426
return False
2527

2628

29+
error_chars = set(string.ascii_uppercase + string.ascii_lowercase + " " + "!")
30+
31+
2732
class ResponseMessage(Message):
2833
"""
2934
The basic error response
3035
"""
31-
c_param = {"error": SINGLE_OPTIONAL_STRING,
32-
"error_description": SINGLE_OPTIONAL_STRING,
33-
"error_uri": SINGLE_OPTIONAL_STRING}
36+
c_param = {
37+
"error": SINGLE_OPTIONAL_STRING,
38+
"error_description": SINGLE_OPTIONAL_STRING,
39+
"error_uri": SINGLE_OPTIONAL_STRING
40+
}
41+
42+
def verify(self, **kwargs):
43+
if "error_description" in self:
44+
# Verify that the characters used are within the allow ranges
45+
# %x20-21 / %x23-5B / %x5D-7E
46+
if all(x in error_chars for x in self["error_description"]):
47+
raise ValueError("Characters outside allowed set")
3448

3549

3650
class AuthorizationErrorResponse(ResponseMessage):
@@ -40,22 +54,26 @@ class AuthorizationErrorResponse(ResponseMessage):
4054
c_param = ResponseMessage.c_param.copy()
4155
c_param.update({"state": SINGLE_OPTIONAL_STRING})
4256
c_allowed_values = ResponseMessage.c_allowed_values.copy()
43-
c_allowed_values.update({"error": ["invalid_request",
44-
"unauthorized_client",
45-
"access_denied",
46-
"unsupported_response_type",
47-
"invalid_scope", "server_error",
48-
"temporarily_unavailable"]})
57+
c_allowed_values.update({
58+
"error": ["invalid_request",
59+
"unauthorized_client",
60+
"access_denied",
61+
"unsupported_response_type",
62+
"invalid_scope", "server_error",
63+
"temporarily_unavailable"]
64+
})
4965

5066

5167
class TokenErrorResponse(ResponseMessage):
5268
"""
5369
Error response from the token endpoint
5470
"""
55-
c_allowed_values = {"error": ["invalid_request", "invalid_client",
56-
"invalid_grant", "unauthorized_client",
57-
"unsupported_grant_type",
58-
"invalid_scope"]}
71+
c_allowed_values = {
72+
"error": ["invalid_request", "invalid_client",
73+
"invalid_grant", "unauthorized_client",
74+
"unsupported_grant_type",
75+
"invalid_scope"]
76+
}
5977

6078

6179
class AccessTokenRequest(Message):
@@ -245,6 +263,63 @@ class TokenIntrospectionResponse(Message):
245263
}
246264

247265

266+
class JWTSecuredAuthorizationRequest(AuthorizationRequest):
267+
c_param = AuthorizationRequest.c_param.copy()
268+
c_param.update({
269+
"request": SINGLE_OPTIONAL_STRING,
270+
"request_uri": SINGLE_OPTIONAL_STRING
271+
})
272+
273+
def verify(self, **kwargs):
274+
if "request" in self:
275+
_vc_name = verified_claim_name("request")
276+
if _vc_name in self:
277+
del self[_vc_name]
278+
279+
args = {}
280+
for arg in ["keyjar", "opponent_id", "sender", "alg", "encalg",
281+
"encenc"]:
282+
try:
283+
args[arg] = kwargs[arg]
284+
except KeyError:
285+
pass
286+
287+
_req = AuthorizationRequest().from_jwt(str(self["request"]), **args)
288+
self.update(_req)
289+
self[_vc_name] = _req
290+
elif "request_uri" not in self:
291+
raise MissingAttribute("One of request or request_uri must be present")
292+
293+
return True
294+
295+
296+
class PushedAuthorizationRequest(AuthorizationRequest):
297+
c_param = AuthorizationRequest.c_param.copy()
298+
c_param.update({
299+
"request": SINGLE_OPTIONAL_STRING
300+
})
301+
302+
def verify(self, **kwargs):
303+
if "request" in self:
304+
_vc_name = verified_claim_name("request")
305+
if _vc_name in self:
306+
del self[_vc_name]
307+
308+
args = {}
309+
for arg in ["keyjar", "opponent_id", "sender", "alg", "encalg",
310+
"encenc"]:
311+
try:
312+
args[arg] = kwargs[arg]
313+
except KeyError:
314+
pass
315+
316+
_req = AuthorizationRequest().from_jwt(str(self["request"]), **args)
317+
self.update(_req)
318+
self[_vc_name] = _req
319+
320+
return True
321+
322+
248323
def factory(msgtype, **kwargs):
249324
"""
250325
Factory method that can be used to easily instansiate a class instance

0 commit comments

Comments
 (0)