From fd7c078a8b622a28a2f64a69a3878c1a8aa16a2f Mon Sep 17 00:00:00 2001 From: adamscmRH Date: Tue, 27 Feb 2018 10:50:48 -0500 Subject: [PATCH 1/2] update docs --- docs/auth/oauth.md | 85 ++++++++++++++++++++------------------------ docs/auth/session.md | 9 +++-- 2 files changed, 45 insertions(+), 49 deletions(-) diff --git a/docs/auth/oauth.md b/docs/auth/oauth.md index 8f46dcc8af..f7dc7d88c7 100644 --- a/docs/auth/oauth.md +++ b/docs/auth/oauth.md @@ -76,21 +76,10 @@ On RBAC side: - Other normal users will only be able to see, update and delete their own applications, but cannot create any new applications. -Note a default new application will be created for each new user. So each new user is supposed to see -at least one application available to them. + Tokens, on the other hand, are resources used to actually authenticate incoming requests and mask the -permissions of underlying user. Tokens can be created by POSTing to `/api/v2/tokens/` -endpoint by providing `application` and `scope` fields to point to related application and specify -token scope; or POSTing to `/api/applications//tokens/` by providing only `scope`, while -the parent application will be automatically linked. - -# More Docs Coming Soon -Note a default new application will be created for each new user. So each new user is supposed to see -at least one application available to them. - -Tokens, on the other hand, are resources used to actually authenticate incoming requests and mask the -permissions of underlying user. Tokens can be created by POSTing to `/api/v2/tokens/` +permissions of the underlying user. Tokens can be created by POSTing to `/api/v2/tokens/` endpoint by providing `application` and `scope` fields to point to related application and specify token scope; or POSTing to `/api/applications//tokens/` by providing only `scope`, while the parent application will be automatically linked. @@ -99,42 +88,45 @@ Individual tokens will be accessible via their primary keys: `/api//me/oauth/tokens//`. Here is a typical token: ``` { - "id": 17, - "type": "access_token", - "url": "/api/v2/me/oauth/tokens/17/", + "id": 4, + "type": "o_auth2_access_token", + "url": "/api/v2/tokens/4/", "related": { "user": "/api/v2/users/1/", - "application": "/api/v2/me/oauth/applications/4/", - "activity_stream": "/api/v2/me/oauth/tokens/17/activity_stream/" + "application": "/api/v2/applications/1/", + "activity_stream": "/api/v2/tokens/4/activity_stream/" }, "summary_fields": { "application": { - "id": 4, - "name": "admin's token", - "client_id": "D6SwhKbfp2LuUjkmiUpMMYFyNqhpv5PTVci7eXTT" + "id": 1, + "name": "Default application for root", + "client_id": "mcU5J5uGQcEQMgAZyr5JUnM3BqBJpgbgL9fLOVch" }, "user": { "id": 1, - "username": "admin", + "username": "root", "first_name": "", "last_name": "" } }, - "created": "2017-12-12T16:48:10.489550Z", - "modified": "2017-12-12T16:48:10.522189Z", + "created": "2018-02-23T14:39:32.618932Z", + "modified": "2018-02-23T14:39:32.643626Z", + "description": "App Token Test", "user": 1, - "token": "kqHqxfpHGRRBXLNCOXxT5Zt3tpJogn", - "refresh_token": "miZq3hqSugvYxhzdQYJIBDgIHxJPnT", - "application": 4, - "expires": "2017-12-13T02:48:10.488180Z", + "token": "*************", + "refresh_token": "**************", + "application": 1, + "expires": "2018-02-24T00:39:32.618279Z", "scope": "read" -} +}, ``` -For an OAuth token, the only fully mutable field is `scope`. The `application` field is *immutable +For an OAuth 2 token, the only fully mutable field is `scope`. The `application` field is *immutable on update*, and all other fields are totally immutable, and will be auto-populated during creation: `user` field will be the `user` field of related application; `expires` will be generated according to Tower configuration setting `OAUTH2_PROVIDER`; `token` and `refresh_token` will be auto-generated -to be non-crashing random strings. +to be non-crashing random strings. Both application tokens and personal access tokens will be shown +at the `/api/v2/tokens/` endpoint. Personal access tokens can be identified by the applications field +being `null`. On RBAC side: - A user will be able to create a token if they are able to see the related application; @@ -158,39 +150,40 @@ According to OAuth 2 specification, users should be able to acquire, revoke and token. In AWX the equivalent, and the easiest, way of doing that is creating a token, deleting a token, and deleting a token quickly followed by creating a new one. -On the other hand, the specification also provides standard ways of doing those. RFC 6749 elaborates -on those topics, but in summary, an OAuth token is officially acquired via authorization using +The specification also provides standard ways of doing this though. RFC 6749 elaborates +on those topics, but in summary, an OAuth 2 token is officially acquired via authorization using authorization information provided by applications (special application fields mentioned above). -There are dedicated endpoints for authorization and acquiring tokens. The token acquire endpoint -is also responsible for token refresh, and token revoke is done by a dedicated token revoke endpoint. +There are dedicated endpoints for authorization and acquiring tokens. The `token` endpoint +is also responsible for token refresh, and token revoke can be done by the dedicated token revoke endpoint. -In AWX, our OAuth system is built on top of +In AWX, our OAuth 2 system is built on top of [Django Oauth Toolkit](https://django-oauth-toolkit.readthedocs.io/en/latest/), which provides full support on standard authorization, token revoke and refresh. AWX implements them and puts related endpoints under `/api/o/` endpoint. Detailed examples on the most typical usage of those endpoints are available as description text of `/api/o/`. #### Token scope mask over RBAC system -The scope of an OAuth token is a space-separated string composed of keywords like 'read' and 'write'. +The scope of an OAuth 2 token is a space-separated string composed of keywords like 'read' and 'write'. These keywords are configurable and used to specify permission level of the authenticated API client. -For the initial OAuth implementation, we use the most simple scope configuration, where the only +For the initial OAuth 2 implementation, we use the most simple scope configuration, where the only valid scope keywords are 'read' and 'write'. Read and write scopes provide a mask layer over the RBAC permission system of AWX. In specific, a -'write' scope gives the authenticated user full permissions the RBAC system provides, while 'read' +'write' scope gives the authenticated user the full permissions the RBAC system provides, while 'read' scope gives the authenticated user only read permissions the RBAC system provides. -For example, if a user has admin permission to a job template, she can both see and modify, launch -and delete the job template if authenticated via session or basic auth. On the other hand, if she -is authenticated using OAuth token, and the related token scope is 'read', she can only see but -not manipulate or launch the job template, despite she has admin role over it; if the token scope is -'write' or 'read write', she can take full advantage of the job template as its admin. +For example, if a user has admin permission to a job template, he/she can both see and modify, launch +and delete the job template if authenticated via session or basic auth. On the other hand, if the user +is authenticated using OAuth 2 token, and the related token scope is 'read', the user can only see but +not manipulate or launch the job template, despite being an admin. If the token scope is +'write' or 'read write', she can take full advantage of the job template as its admin. Note, that 'write' +implies 'read' as well. ## Acceptance Criteria -* All CRUD operations for OAuth applications and tokens should function as described. +* All CRUD operations for OAuth 2 applications and tokens should function as described. * RBAC rules applied to OAuth applications and tokens should behave as described. * A default application should be auto-created for each new user. -* Incoming requests using unexpired OAuth token correctly in authentication header should be able +* Incoming requests using unexpired OAuth 2 token correctly in authentication header should be able to successfully authenticate themselves. * Token scope mask over RBAC should work as described. * Tower configuration setting `OAUTH2_PROVIDER` should be configurable and function as described. diff --git a/docs/auth/session.md b/docs/auth/session.md index ac125caeb4..1e31375adc 100644 --- a/docs/auth/session.md +++ b/docs/auth/session.md @@ -6,15 +6,18 @@ will be replaced by OAuth 2 tokens. Session authentication is a safer way of utilizing HTTP(S) cookies: -Theoretically, user can provide authentication information, like username and password, as part of the +Theoretically, the user can provide authentication information, like username and password, as part of the `Cookie` header, but this method is vulnerable to cookie hijacks, where crackers can see and steal user information from cookie payload. Session authentication, on the other hand, sets a single `session_id` cookie. The session_id is *a random string which will be mapped to user authentication informations by server*. Crackers who -hijacks cookie will only get the session_id itself, which does not imply any critical user info, is valid only for +hijack cookies will only get the session_id itself, which does not imply any critical user info, is valid only for a limited time, and can be revoked at any time. +> Note: The CSRF token will by default allow HTTP. To increase security, the `CSRF_COOKIE_SECURE` setting should +be set to False. + ## Usage In session authentication, users log in using the `/api/login/` endpoint. A GET to `/api/login/` displays the @@ -39,7 +42,7 @@ The session_id is provided as a return `Set-Cookie` header. Here is a typical on Set-Cookie: sessionid=lwan8l5ynhrqvps280rg5upp7n3yp6ds; expires=Tue, 21-Nov-2017 16:33:13 GMT; httponly; Max-Age=1209600; Path=/ ``` Any client should follow the standard rules of [cookie protocol](https://tools.ietf.org/html/rfc6265) to -parse that header to obtain information about the session, such as session cookie name (`sessionid`), +parse that header to obtain information about the session, such as session cookie name (`session_id`), session cookie value, expiration date, duration, etc. The duration of the cookie is configurable by Tower Configuration setting `SESSION_COOKIE_AGE` under From 9b195bc80f203e46a9ed8870cef83f051c07f830 Mon Sep 17 00:00:00 2001 From: adamscmRH Date: Thu, 8 Mar 2018 12:31:40 -0500 Subject: [PATCH 2/2] fix oauth docs --- .../api/api_o_auth_authorization_root_view.md | 10 +++---- docs/auth/oauth.md | 29 +++++++++++-------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/awx/api/templates/api/api_o_auth_authorization_root_view.md b/awx/api/templates/api/api_o_auth_authorization_root_view.md index 40523ad9dc..de3c627208 100644 --- a/awx/api/templates/api/api_o_auth_authorization_root_view.md +++ b/awx/api/templates/api/api_o_auth_authorization_root_view.md @@ -51,7 +51,7 @@ Vary:Accept-Language, Cookie By inspecting the fragment part of redirect URL given by `Location` header, we can get access token (given by `access_token` key) as well as other standard fields specified in OAuth spec. Internally an OAuth token is created under the given application. Verify by -`GET /api/v2/me/oauth/tokens/?token=0lVJJkolFTwYawHyGkk7NTmSKdzBen` +`GET /api/v2/tokens/?token=0lVJJkolFTwYawHyGkk7NTmSKdzBen` ```text HTTP 200 OK Allow: GET, POST, HEAD, OPTIONS @@ -176,7 +176,7 @@ Internally, the refresh operation deletes the existing token and a new token is after, with information like scope and related application identical to the original one. We can verify by checking the new token is present ```text -GET /api/v2/me/oauth/tokens/?token=NDInWxGJI4iZgqpsreujjbvzCfJqgR +GET /api/v2/tokens/?token=NDInWxGJI4iZgqpsreujjbvzCfJqgR HTTP 200 OK Allow: GET, POST, HEAD, OPTIONS @@ -208,7 +208,7 @@ X-API-Time: 0.021s ``` and the old token is deleted. ```text -GET /api/v2/me/oauth/tokens/?token=omMFLk7UKpB36WN2Qma9H3gbwEBSOc +GET /api/v2/tokens/?token=omMFLk7UKpB36WN2Qma9H3gbwEBSOc HTTP 200 OK Allow: GET, POST, HEAD, OPTIONS @@ -234,7 +234,7 @@ an existing token to revoke: { "id": 30, "type": "access_token", - "url": "/api/v2/me/oauth/tokens/30/", + "url": "/api/v2/tokens/30/", ... "user": null, "token": "rQONsve372fQwuc2pn76k3IHDCYpi7", @@ -265,7 +265,7 @@ Strict-Transport-Security: max-age=15768000 ``` We can verify the effect by checking if the token is no longer present. ```text -GET /api/v2/me/oauth/tokens/?token=rQONsve372fQwuc2pn76k3IHDCYpi7 +GET /api/v2//tokens/?token=rQONsve372fQwuc2pn76k3IHDCYpi7 HTTP 200 OK Allow: GET, POST, HEAD, OPTIONS diff --git a/docs/auth/oauth.md b/docs/auth/oauth.md index f7dc7d88c7..538f4e4e67 100644 --- a/docs/auth/oauth.md +++ b/docs/auth/oauth.md @@ -81,11 +81,11 @@ On RBAC side: Tokens, on the other hand, are resources used to actually authenticate incoming requests and mask the permissions of the underlying user. Tokens can be created by POSTing to `/api/v2/tokens/` endpoint by providing `application` and `scope` fields to point to related application and specify -token scope; or POSTing to `/api/applications//tokens/` by providing only `scope`, while +token scope; or POSTing to `/api/v2/applications//tokens/` by providing only `scope`, while the parent application will be automatically linked. Individual tokens will be accessible via their primary keys: -`/api//me/oauth/tokens//`. Here is a typical token: +`/api//tokens//`. Here is a typical token: ``` { "id": 4, @@ -120,13 +120,14 @@ Individual tokens will be accessible via their primary keys: "scope": "read" }, ``` -For an OAuth 2 token, the only fully mutable field is `scope`. The `application` field is *immutable -on update*, and all other fields are totally immutable, and will be auto-populated during creation: -`user` field will be the `user` field of related application; `expires` will be generated according -to Tower configuration setting `OAUTH2_PROVIDER`; `token` and `refresh_token` will be auto-generated -to be non-crashing random strings. Both application tokens and personal access tokens will be shown -at the `/api/v2/tokens/` endpoint. Personal access tokens can be identified by the applications field -being `null`. +For an OAuth 2 token, the only fully mutable fields are `scope` and `description`. The `application` +field is *immutable on update*, and all other fields are totally immutable, and will be auto-populated +during creation +* `user` field will be the `user` field of related application +* `expires` will be generated according to Tower configuration setting `OAUTH2_PROVIDER` +* `token` and `refresh_token` will be auto-generated to be non-clashing random strings. +Both application tokens and personal access tokens will be shown at the `/api/v2/tokens/` +endpoint. Personal access tokens can be identified by the `application` field being `null`. On RBAC side: - A user will be able to create a token if they are able to see the related application; @@ -139,8 +140,12 @@ On RBAC side: #### Using OAuth 2 token system as a Personal Access Token (PAT) The most common usage of OAuth 2 is authenticating users. The `token` field of a token is used as part of the HTTP authentication header, in the format `Authorization: Bearer `. This _Bearer_ -token can be obtained by doing a curl to the `/api/o/token/` endpoint as shown in `api_o_auth_authorization_root_view.md`. - +token can be obtained by doing a curl to the `/api/o/token/` endpoint. For example: +``` +curl -ku root:reverse -H "Content-Type: application/json" -X POST \ +-d '{"description":"Tower CLI","application":null,"scope":"read"}' \ +https://localhost:8043/api/v2/users/1/personal_tokens/ | python -m json.tool +``` Here is an example of using that PAT to access an API endpoint using `curl`: ``` curl -H "Authorization: Bearer kqHqxfpHGRRBXLNCOXxT5Zt3tpJogn" http://localhost:8013/api/v2/credentials/ @@ -150,7 +155,7 @@ According to OAuth 2 specification, users should be able to acquire, revoke and token. In AWX the equivalent, and the easiest, way of doing that is creating a token, deleting a token, and deleting a token quickly followed by creating a new one. -The specification also provides standard ways of doing this though. RFC 6749 elaborates +The specification also provides standard ways of doing this. RFC 6749 elaborates on those topics, but in summary, an OAuth 2 token is officially acquired via authorization using authorization information provided by applications (special application fields mentioned above). There are dedicated endpoints for authorization and acquiring tokens. The `token` endpoint