Skip to content

Commit f309451

Browse files
committed
Update README
1 parent 69a7e62 commit f309451

File tree

1 file changed

+161
-12
lines changed

1 file changed

+161
-12
lines changed

README.rst

Lines changed: 161 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
------------------
3180
In 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

Comments
 (0)