This repository has been archived by the owner on Mar 3, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
/
create_oauth2_client.py
160 lines (134 loc) · 5.58 KB
/
create_oauth2_client.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
"""
Management command used to create an OAuth2 client in the database.
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import json
from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand, CommandError
from provider.constants import CONFIDENTIAL, PUBLIC
from provider.oauth2.models import Client
from ...models import TrustedClient
ARG_STRING = '<url> <redirect_uri> <client_type: "confidential" | "public">'
class Command(BaseCommand):
"""
create_oauth2_client command class
"""
help = 'Create a new OAuth2 Client. Outputs a serialized representation of the newly-created Client.'
def add_arguments(self, parser):
super(Command, self).add_arguments(parser)
# Required positional arguments.
parser.add_argument(
'url',
help="Url."
)
parser.add_argument(
'redirect_uri',
help="Redirect URI."
)
parser.add_argument(
'client_type',
help="Client type."
)
# Optional options.
parser.add_argument(
'-u',
'--username',
help="Username of a user to associate with the Client."
)
parser.add_argument(
'-n',
'--client_name',
help="String to assign as the Client name."
)
parser.add_argument(
'-i',
'--client_id',
help="String to assign as the Client ID."
)
parser.add_argument(
'-s',
'--client_secret',
help="String to assign as the Client secret. Should not be shared."
)
parser.add_argument(
'-t',
'--trusted',
action='store_true',
help="Designate the Client as trusted. Trusted Clients bypass the user consent "
"form typically displayed after validating the user's credentials."
)
parser.add_argument(
'--logout_uri',
help="Client logout URI. This value will be used for single sign out."
)
def handle(self, *args, **options):
self._clean_required_args(options['url'], options['redirect_uri'], options['client_type'])
self._parse_options(options)
client_id = self.fields.get('client_id')
trusted = self.fields.pop('trusted')
# Check if client ID is already in use. If so, fetch existing Client and update fields.
client_id_claimed = Client.objects.filter(client_id=client_id).exists()
if client_id_claimed:
client = Client.objects.get(client_id=client_id)
for key, value in self.fields.items():
setattr(client, key, value)
client.save()
else:
client = Client.objects.create(**self.fields)
if trusted:
TrustedClient.objects.get_or_create(client=client)
else:
try:
TrustedClient.objects.get(client=client).delete()
except TrustedClient.DoesNotExist:
pass
serialized = json.dumps(client.serialize(), indent=4)
self.stdout.write(serialized)
def _clean_required_args(self, url, redirect_uri, client_type):
"""
Validate and clean the command's arguments.
Arguments:
url (str): Client's application URL.
redirect_uri (str): Client application's OAuth2 callback URI.
client_type (str): Client's type, indicating whether the Client application
is capable of maintaining the confidentiality of its credentials (e.g., running on a
secure server) or is incapable of doing so (e.g., running in a browser).
Raises:
CommandError, if the URLs provided are invalid, or if the client type provided is invalid.
"""
# Validate and map client type to the appropriate django-oauth2-provider constant
client_type = client_type.lower()
client_type = {
'confidential': CONFIDENTIAL,
'public': PUBLIC
}.get(client_type)
if client_type is None:
raise CommandError("Client type provided is invalid. Please use one of 'confidential' or 'public'.")
self.fields = { # pylint: disable=attribute-defined-outside-init
'url': url,
'redirect_uri': redirect_uri,
'client_type': client_type,
}
def _parse_options(self, options):
"""Parse the command's options.
Arguments:
options (dict): Options with which the command was called.
Raises:
CommandError, if a user matching the provided username does not exist.
"""
for key in ('username', 'client_name', 'client_id', 'client_secret', 'trusted', 'logout_uri'):
value = options.get(key)
if value is not None:
self.fields[key] = value
username = self.fields.pop('username', None)
if username is not None:
try:
user_model = get_user_model()
self.fields['user'] = user_model.objects.get(username=username)
except user_model.DoesNotExist:
raise CommandError("User matching the provided username does not exist.")
# The keyword argument 'name' conflicts with that of `call_command()`. We instead
# use 'client_name' up to this point, then swap it out for the expected field, 'name'.
client_name = self.fields.pop('client_name', None)
if client_name is not None:
self.fields['name'] = client_name