mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 10:00:01 -03:30
* Changing session cookie name and added a way for clients to know what the key name is * Adding session information to docs * Fixing how awxkit gets the session id header
This commit is contained in:
parent
895c05a84a
commit
cb57752903
@ -99,6 +99,7 @@ class LoggedLoginView(auth_views.LoginView):
|
||||
current_user = smart_text(JSONRenderer().render(current_user.data))
|
||||
current_user = urllib.parse.quote('%s' % current_user, '')
|
||||
ret.set_cookie('current_user', current_user, secure=settings.SESSION_COOKIE_SECURE or None)
|
||||
ret.setdefault('X-API-Session-Cookie-Name', getattr(settings, 'SESSION_COOKIE_NAME', 'awx_sessionid'))
|
||||
|
||||
return ret
|
||||
else:
|
||||
|
||||
@ -252,6 +252,10 @@ SESSION_COOKIE_SECURE = True
|
||||
# Note: This setting may be overridden by database settings.
|
||||
SESSION_COOKIE_AGE = 1800
|
||||
|
||||
# Name of the cookie that contains the session information.
|
||||
# Note: Changing this value may require changes to any clients.
|
||||
SESSION_COOKIE_NAME = 'awx_sessionid'
|
||||
|
||||
# Maximum number of per-user valid, concurrent sessions.
|
||||
# -1 is unlimited
|
||||
# Note: This setting may be overridden by database settings.
|
||||
|
||||
@ -46,6 +46,7 @@ class CompleteView(BaseRedirectView):
|
||||
current_user = smart_text(JSONRenderer().render(current_user.data))
|
||||
current_user = urllib.parse.quote('%s' % current_user, '')
|
||||
response.set_cookie('current_user', current_user, secure=settings.SESSION_COOKIE_SECURE or None)
|
||||
response.setdefault('X-API-Session-Cookie-Name', getattr(settings, 'SESSION_COOKIE_NAME', 'awx_sessionid'))
|
||||
return response
|
||||
|
||||
|
||||
|
||||
@ -33,6 +33,10 @@ class Connection(object):
|
||||
def __init__(self, server, verify=False):
|
||||
self.server = server
|
||||
self.verify = verify
|
||||
# Note: We use the old sessionid here incase someone is trying to connect to an older AWX version
|
||||
# There is a check below so that if AWX returns an X-API-Session-Cookie-Name we will grab it and
|
||||
# connect with the new session cookie name.
|
||||
self.session_cookie_name = 'sessionid'
|
||||
|
||||
if not self.verify:
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
@ -49,8 +53,13 @@ class Connection(object):
|
||||
_next = kwargs.get('next')
|
||||
if _next:
|
||||
headers = self.session.headers.copy()
|
||||
self.post('/api/login/', headers=headers, data=dict(username=username, password=password, next=_next))
|
||||
self.session_id = self.session.cookies.get('sessionid')
|
||||
response = self.post('/api/login/', headers=headers, data=dict(username=username, password=password, next=_next))
|
||||
# The login causes a redirect so we need to search the history of the request to find the header
|
||||
for historical_response in response.history:
|
||||
if 'X-API-Session-Cookie-Name' in historical_response.headers:
|
||||
self.session_cookie_name = historical_response.headers.get('X-API-Session-Cookie-Name')
|
||||
|
||||
self.session_id = self.session.cookies.get(self.session_cookie_name, None)
|
||||
self.uses_session_cookie = True
|
||||
else:
|
||||
self.session.auth = (username, password)
|
||||
@ -61,7 +70,7 @@ class Connection(object):
|
||||
|
||||
def logout(self):
|
||||
if self.uses_session_cookie:
|
||||
self.session.cookies.pop('sessionid', None)
|
||||
self.session.cookies.pop(self.session_cookie_name, None)
|
||||
else:
|
||||
self.session.auth = None
|
||||
|
||||
|
||||
@ -95,12 +95,12 @@ def as_user(v, username, password=None):
|
||||
# requests doesn't provide interface for retrieving
|
||||
# domain segregated cookies other than iterating.
|
||||
for cookie in connection.session.cookies:
|
||||
if cookie.name == 'sessionid':
|
||||
if cookie.name == connection.session_cookie_name:
|
||||
session_id = cookie.value
|
||||
domain = cookie.domain
|
||||
break
|
||||
if session_id:
|
||||
del connection.session.cookies['sessionid']
|
||||
del connection.session.cookies[connection.session_cookie_name]
|
||||
if access_token:
|
||||
kwargs = dict(token=access_token)
|
||||
else:
|
||||
@ -114,9 +114,9 @@ def as_user(v, username, password=None):
|
||||
if config.use_sessions:
|
||||
if access_token:
|
||||
connection.session.auth = None
|
||||
del connection.session.cookies['sessionid']
|
||||
del connection.session.cookies[connection.session_cookie_name]
|
||||
if session_id:
|
||||
connection.session.cookies.set('sessionid', session_id, domain=domain)
|
||||
connection.session.cookies.set(connection.session_cookie_name, session_id, domain=domain)
|
||||
else:
|
||||
connection.session.auth = previous_auth
|
||||
|
||||
|
||||
@ -51,7 +51,9 @@ class WSClient(object):
|
||||
|
||||
# Subscription group types
|
||||
|
||||
def __init__(self, token=None, hostname='', port=443, secure=True, session_id=None, csrftoken=None, add_received_time=False):
|
||||
def __init__(
|
||||
self, token=None, hostname='', port=443, secure=True, session_id=None, csrftoken=None, add_received_time=False, session_cookie_name='awx_sessionid'
|
||||
):
|
||||
# delay this import, because this is an optional dependency
|
||||
import websocket
|
||||
|
||||
@ -78,7 +80,7 @@ class WSClient(object):
|
||||
if self.token is not None:
|
||||
auth_cookie = 'token="{0.token}";'.format(self)
|
||||
elif self.session_id is not None:
|
||||
auth_cookie = 'sessionid="{0.session_id}"'.format(self)
|
||||
auth_cookie = '{1}="{0.session_id}"'.format(self, session_cookie_name)
|
||||
if self.csrftoken:
|
||||
auth_cookie += ';csrftoken={0.csrftoken}'.format(self)
|
||||
else:
|
||||
|
||||
@ -6,9 +6,9 @@ Session authentication is a safer way of utilizing HTTP(S) cookies. Theoreticall
|
||||
`Cookie` header, but this method is vulnerable to cookie hijacks, where crackers can see and steal user
|
||||
information from the 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
|
||||
hijack cookies will only get the `session_id` itself, which does not imply any critical user info, is valid only for
|
||||
Session authentication, on the other hand, sets a single `awx_sessionid` cookie. The `awx_sessionid`
|
||||
is *a random string which will be mapped to user authentication information by the server*. Crackers who
|
||||
hijack cookies will only get the `awx_sessionid` 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
|
||||
@ -34,22 +34,27 @@ be provided in the form:
|
||||
* `next`: The path of the redirect destination, in API browser `"/api/"` is used.
|
||||
* `csrfmiddlewaretoken`: The CSRF token, usually populated by using Django template `{% csrf_token %}`.
|
||||
|
||||
The `session_id` is provided as a return `Set-Cookie` header. Here is a typical one:
|
||||
The `awx_session_id` is provided as a return `Set-Cookie` header. Here is a typical one:
|
||||
```
|
||||
Set-Cookie: sessionid=lwan8l5ynhrqvps280rg5upp7n3yp6ds; expires=Tue, 21-Nov-2017 16:33:13 GMT; httponly; Max-Age=1209600; Path=/
|
||||
Set-Cookie: awx_sessionid=lwan8l5ynhrqvps280rg5upp7n3yp6ds; expires=Tue, 21-Nov-2017 16:33:13 GMT; httponly; Max-Age=1209600; Path=/
|
||||
```
|
||||
|
||||
In addition, when the `awx_sessionid` a header called `X-API-Session-Cookie-Name` this header will only be displayed once on a successful logging and denotes the name of the session cookie name. By default this is `awx_sessionid` but can be changed (see below).
|
||||
|
||||
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 (`session_id`),
|
||||
parse that header to obtain information about the session, such as session cookie name (`awx_sessionid`),
|
||||
session cookie value, expiration date, duration, etc.
|
||||
|
||||
The name of the cookie is configurable by Tower Configuration setting `SESSION_COOKIE_NAME` under the category `authentication`. It is a string. The default session cookie name is `awx_sessionid`.
|
||||
|
||||
The duration of the cookie is configurable by Tower Configuration setting `SESSION_COOKIE_AGE` under
|
||||
category `authentication`. It is an integer denoting the number of seconds the session cookie should
|
||||
live. The default session cookie age is two weeks.
|
||||
|
||||
After a valid session is acquired, a client should provide the `session_id` as a cookie for subsequent requests
|
||||
After a valid session is acquired, a client should provide the `awx_sessionid` as a cookie for subsequent requests
|
||||
in order to be authenticated. For example:
|
||||
```
|
||||
Cookie: sessionid=lwan8l5ynhrqvps280rg5upp7n3yp6ds; ...
|
||||
Cookie: awx_sessionid=lwan8l5ynhrqvps280rg5upp7n3yp6ds; ...
|
||||
```
|
||||
|
||||
User should use the `/api/logout/` endpoint to log out. In the API browser, a logged-in user can do that by
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user