@@ -25,24 +25,173 @@ Quick start
2525 url(r'^authorize/', obtain_authorization_token),
2626 ]
2727
28+ Additional data in authorization tokens
29+ ---------------------------------------
30+ For example, you may want to include an `account ` field in your JWT authorization tokens,
31+ so that `otherapp ` will know about the user's permissions. To do this, you may need to override
32+ the ObtainAuthorizationTokenView and AuthorizationTokenSerializer::
2833
29- Authentication class
30- --------------------
34+ class ObtainAuthorizationTokenView(rest_framework_sso.views.ObtainAuthorizationTokenView):
35+ """
36+ Returns a JSON Web Token that can be used for authenticated requests.
37+ """
38+ serializer_class = AuthorizationTokenSerializer
39+
40+
41+ class AuthorizationTokenSerializer(QuerySetReadableMixin, serializers.Serializer):
42+ account = serializers.HyperlinkedRelatedField(
43+ queryset=Account.objects.all(),
44+ required=True,
45+ view_name='api:account-detail',
46+ )
47+
48+ class Meta:
49+ fields = ['account']
50+
51+ Replace the authorization token view in your URL conf::
52+
53+ urlpatterns = [
54+ url(r'^authorize/$', ObtainAuthorizationTokenView.as_view()),
55+ ...
56+ ]
57+
58+ Add the `account ` keyword argument to the `create_authorization_payload ` function::
59+
60+ from rest_framework_sso import claims
61+
62+ def create_authorization_payload(session_token, user, account, **kwargs):
63+ return {
64+ claims.TOKEN: claims.TOKEN_AUTHORIZATION,
65+ claims.SESSION_ID: session_token.pk,
66+ claims.USER_ID: user.pk,
67+ claims.EMAIL: user.email,
68+ 'account': account.pk,
69+ }
70+
71+ You will need to activete this function in the settings::
72+
73+ REST_FRAMEWORK_SSO = {
74+ 'CREATE_AUTHORIZATION_PAYLOAD': 'myapp.authentication.create_authorization_payload',
75+ ...
76+ }
77+
78+ JWT Authentication
79+ ------------------
3180In order to get-or-create User accounts automatically within your microservice apps,
32- you can use the following DRF Authentication class template ::
81+ you may need to write your custom JWT payload authentication function ::
3382
83+ from django.contrib.auth import get_user_model
3484 from rest_framework_sso import claims
3585
36- class Authentication(rest_framework_sso.authentication.JWTAuthentication):
37- def authenticate_credentials(self, payload):
38- user_model = get_user_model()
86+ def authenticate_payload(payload):
87+ user_model = get_user_model()
88+ user, created = user_model.objects.get_or_create(
89+ service=payload.get(claims.ISSUER),
90+ external_id=payload.get(claims.USER_ID),
91+ )
92+ if not user.is_active:
93+ raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
94+ return user
95+
3996
40- user, created = user_model.objects.get_or_create(
41- service=payload.get(claims.ISSUER),
42- external_id=payload.get(claims.USER_ID),
97+ Enable authenticate_payload function in REST_FRAMEWORK_SSO settings::
98+
99+ REST_FRAMEWORK_SSO = {
100+ 'AUTHENTICATE_PAYLOAD': 'otherapp.authentication.authenticate_payload',
101+ ...
102+ }
103+
104+ Enable JWT authentication in the REST_FRAMEWORK settings::
105+
106+ REST_FRAMEWORK = {
107+ 'DEFAULT_AUTHENTICATION_CLASSES': (
108+ 'rest_framework_sso.authentication.JWTAuthentication',
109+ 'rest_framework.authentication.SessionAuthentication',
110+ ...
111+ ),
112+ ...
113+ }
114+
115+ Requests that have been successfully authenticated with JWTAuthentication contain
116+ the JWT payload data in the `request.auth ` variable. This data can be used in your
117+ API views/viewsets to handle permissions, for example::
118+
119+ from rest_framework_sso import claims
120+
121+ class UserViewSet(viewsets.ReadOnlyModelViewSet):
122+ serializer_class = UserSerializer
123+ queryset = User.objects.none()
124+
125+ def get_queryset(self):
126+ if not request.user.is_authenticated() or not request.auth:
127+ return self.none()
128+ return User.objects.filter(
129+ service=request.auth.get(claims.ISSUER),
130+ external_id=request.auth.get(claims.USER_ID),
43131 )
44132
45- if not user.is_active:
46- raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
133+ Settings
134+ --------
135+ Example settings for project that both issues and validates tokens for `myapp ` and `otherapp `::
136+
137+ REST_FRAMEWORK_SSO = {
138+ 'CREATE_AUTHORIZATION_PAYLOAD': 'myapp.authentication.create_authorization_payload',
139+ 'IDENTITY': 'myapp',
140+ 'SESSION_AUDIENCE': ['myapp'],
141+ 'AUTHORIZATION_AUDIENCE': ['myapp', 'otherapp'],
142+ 'ACCEPTED_ISSUERS': ['myapp'],
143+ 'PUBLIC_KEYS': {
144+ 'myapp': 'keys/myapp_public_key.pem',
145+ },
146+ 'PRIVATE_KEYS': {
147+ 'myapp': 'keys/myapp_private_key.pem',
148+ },
149+ }
150+
151+ Example settings for project that only accepts tokens signed by `myapp ` for `otherapp `::
152+
153+ REST_FRAMEWORK_SSO = {
154+ 'AUTHENTICATE_PAYLOAD': 'otherapp.authentication.authenticate_payload',
155+ 'VERIFY_SESSION_TOKEN': False,
156+ 'IDENTITY': 'otherapp',
157+ 'ACCEPTED_ISSUERS': ['myapp'],
158+ 'PUBLIC_KEYS': {
159+ 'myapp': 'keys/myapp_public_key.pem',
160+ },
161+ }
162+
163+ Full list of settings parameters with their defaults::
164+
165+ REST_FRAMEWORK_SSO = {
166+ 'CREATE_SESSION_PAYLOAD': 'rest_framework_sso.utils.create_session_payload',
167+ 'CREATE_AUTHORIZATION_PAYLOAD': 'rest_framework_sso.utils.create_authorization_payload',
168+ 'ENCODE_JWT_TOKEN': 'rest_framework_sso.utils.encode_jwt_token',
169+ 'DECODE_JWT_TOKEN': 'rest_framework_sso.utils.decode_jwt_token',
170+ 'AUTHENTICATE_PAYLOAD': 'rest_framework_sso.utils.authenticate_payload',
171+
172+ 'ENCODE_ALGORITHM': 'RS256',
173+ 'DECODE_ALGORITHMS': None,
174+ 'VERIFY_SIGNATURE': True,
175+ 'VERIFY_EXPIRATION': True,
176+ 'VERIFY_SESSION_TOKEN': True,
177+ 'EXPIRATION_LEEWAY': 0,
178+ 'SESSION_EXPIRATION': None,
179+ 'AUTHORIZATION_EXPIRATION': datetime.timedelta(seconds=300),
180+
181+ 'IDENTITY': None,
182+ 'SESSION_AUDIENCE': None,
183+ 'AUTHORIZATION_AUDIENCE': None,
184+ 'ACCEPTED_ISSUERS': None,
185+ 'PUBLIC_KEYS': {},
186+ 'PRIVATE_KEYS': {},
187+
188+ 'AUTHENTICATE_HEADER': 'JWT',
189+ }
190+
191+ Generating RSA keys
192+ -------------------
193+ You can use openssl to generate your public/private key pairs::
194+
195+ $ openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
196+ $ openssl rsa -pubout -in private_key.pem -out public_key.pem
47197
48- return user, payload
0 commit comments