-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathclients.py
118 lines (101 loc) · 4.91 KB
/
clients.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# Copyright (c) Sebastian Scholz
# See LICENSE for details.
""" Classes for representing and dealing with oauth2 clients """
from abc import abstractmethod, ABCMeta
try:
from urlparse import urlparse
except ImportError:
# noinspection PyUnresolvedReferences
from urllib.parse import urlparse
from txoauth2.util import isAnyStr
from txoauth2.granttypes import GrantTypes
from txoauth2.errors import InvalidClientAuthenticationError, NoClientAuthenticationError
class ClientStorage(object):
"""
This class's purpose is to manage and give access
to the clients that the server knows via their clientId.
"""
__metaclass__ = ABCMeta
# pylint: disable=no-self-use, unused-argument
def authenticateClient(self, client, request, secret=None):
"""
Authenticate a given client.
:raises OAuth2Error: If the client could not be authenticated.
:param client: The client that should get authenticated.
:param request: The request that may contain the credentials for a client.
:param secret: The client secret, if it could get extracted from the request.
:return: The client that was authenticated by the request.
"""
if secret is not None:
if isinstance(client, PasswordClient) and client.secret == secret:
return client
raise InvalidClientAuthenticationError()
raise NoClientAuthenticationError()
@abstractmethod
def getClient(self, clientId):
"""
Return a Client object representing the client with the given clientId.
:raises KeyError: If no client with the given clientId is found.
:param clientId: The client id of the client.
:return: The Client object.
"""
raise NotImplementedError()
class Client(object):
"""
This class represents a client.
A client is an entity, which is given access to a scope by the user.
The client can use a grant type it is authorized to use to request an access token
with which it can access resources on behalf of the user.
"""
def __init__(self, clientId, redirectUris, authorizedGrantTypes):
"""
:raises ValueError: If one of the argument is not of the expected type
or one of the redirect uris has a fragment or is relative.
:param clientId: The id of this client.
:param redirectUris: A list of urls, which we can redirect to after authorization.
:param authorizedGrantTypes: A list of grant types that this client is authorized
to use to get an access token.
"""
super(Client, self).__init__()
if not isAnyStr(clientId):
raise ValueError('Expected clientId must be a string, got ' + str(type(clientId)))
if not isinstance(redirectUris, list):
raise ValueError('Expected redirectUris to be of type list, got '
+ str(type(redirectUris)))
for uri in redirectUris:
if not isinstance(uri, str):
raise ValueError('Expected the redirectUris to be of type str, got '
+ str(type(uri)))
parsedUri = urlparse(uri)
if parsedUri.fragment != '':
raise ValueError('Got a redirect uri with a fragment: ' + uri)
if parsedUri.netloc == '':
raise ValueError('Got a redirect uri that is not absolute: ' + uri)
if not isinstance(authorizedGrantTypes, list):
raise ValueError('Expected authorizedGrantTypes to be of type list, got '
+ str(type(authorizedGrantTypes)))
authorizedGrantTypes = [grantType.value if isinstance(grantType, GrantTypes) else grantType
for grantType in authorizedGrantTypes]
for grantType in authorizedGrantTypes:
if not isinstance(grantType, str):
raise ValueError('Expected the grant types to be of type str, got '
+ str(type(grantType)))
self.id = clientId # pylint: disable=invalid-name
self.redirectUris = redirectUris
self.authorizedGrantTypes = authorizedGrantTypes
class PublicClient(Client):
"""
This is a public client which is not able to maintain the confidentiality of their
credentials and thus are not required to authenticate themselves.
See: https://tools.ietf.org/html/rfc6749#section-2.1
"""
def __init__(self, *args, **kwargs):
super(PublicClient, self).__init__(*args, **kwargs)
class PasswordClient(Client):
"""
This is a confidential client which authenticates himself with a password/secret.
See: https://tools.ietf.org/html/rfc6749#section-2.3.1
"""
def __init__(self, clientId, redirectUris, authorizedGrantTypes, secret):
super(PasswordClient, self).__init__(clientId, redirectUris, authorizedGrantTypes)
self.secret = secret