Improve auth support

pull/257/head
halcy 2022-11-13 22:32:04 +02:00
rodzic 5b328d479c
commit 24c686f6b2
3 zmienionych plików z 304 dodań i 7 usunięć

Wyświetl plik

@ -486,8 +486,7 @@ class Mastodon:
"""
return Mastodon.__SUPPORTED_MASTODON_VERSION
def auth_request_url(self, client_id=None, redirect_uris="urn:ietf:wg:oauth:2.0:oob",
scopes=__DEFAULT_SCOPES, force_login=False):
def auth_request_url(self, client_id=None, redirect_uris="urn:ietf:wg:oauth:2.0:oob", scopes=__DEFAULT_SCOPES, force_login=False, state=None):
"""
Returns the url that a client needs to request an oauth grant from the server.
@ -501,6 +500,10 @@ class Mastodon:
Pass force_login if you want the user to always log in even when already logged
into web mastodon (i.e. when registering multiple different accounts in an app).
State is the oauth `state`parameter to pass to the server. It is strongly suggested
to use a random, nonguessable value (i.e. nothing meaningful and no incrementing ID)
to preserve security guarantees. It can be left out for non-web login flows.
"""
if client_id is None:
client_id = self.client_id
@ -515,12 +518,11 @@ class Mastodon:
params['redirect_uri'] = redirect_uris
params['scope'] = " ".join(scopes)
params['force_login'] = force_login
params['state'] = state
formatted_params = urlencode(params)
return "".join([self.api_base_url, "/oauth/authorize?", formatted_params])
def log_in(self, username=None, password=None,
code=None, redirect_uri="urn:ietf:wg:oauth:2.0:oob", refresh_token=None,
scopes=__DEFAULT_SCOPES, to_file=None):
def log_in(self, username=None, password=None, code=None, redirect_uri="urn:ietf:wg:oauth:2.0:oob", refresh_token=None, scopes=__DEFAULT_SCOPES, to_file=None):
"""
Get the access token for a user.
@ -588,6 +590,25 @@ class Mastodon:
return response['access_token']
def revoke_access_token(self):
"""
Revoke the oauth token the user is currently authenticated with, effectively removing
the apps access and requiring the user to log in again.
"""
if self.access_token is None:
raise MastodonIllegalArgumentError("Not logged in, do not have a token to revoke.")
if self.client_id is None or self.client_secret is None:
raise MastodonIllegalArgumentError("Client authentication (id + secret) is required to revoke tokens.")
params = collections.OrderedDict([])
params['client_id'] = self.client_id
params['client_secret'] = self.client_secret
params['token'] = self.access_token
self.__api_request('POST', '/oauth/revoke', params)
# We are now logged out, clear token and logged in id
self.access_token = None
self.__logged_in_id = None
@api_version("2.7.0", "2.7.0", "2.7.0")
def create_account(self, username, password, email, agreement=False, reason=None, locale="en", scopes=__DEFAULT_SCOPES, to_file=None):
"""

Wyświetl plik

@ -0,0 +1,253 @@
interactions:
- request:
body: username=mastodonpy_test_2%40localhost%3A3000&password=5fc638e0e53eafd9c4145b6bb852667d&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&grant_type=password&client_id=__MASTODON_PY_TEST_CLIENT_ID&client_secret=__MASTODON_PY_TEST_CLIENT_SECRET&scope=read+write+follow+push
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '271'
Content-Type:
- application/x-www-form-urlencoded
User-Agent:
- tests/v311
method: POST
uri: http://localhost:3000/oauth/token
response:
body:
string: '{"access_token":"s3ZSxpaa2Uhe9EcHankvkfaQZQGiWpdEWIhX7GuhDlk","token_type":"Bearer","scope":"read
write follow push","created_at":1668370881}'
headers:
Cache-Control:
- no-store
Content-Security-Policy:
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
style-src ''self'' http://localhost:3000 ''nonce-pCi2AQ9aKYXwS29cp2OHAg=='';
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
worker-src ''self'' blob: http://localhost:3000'
Content-Type:
- application/json; charset=utf-8
ETag:
- W/"b4c5259bc2edbe94aab5df0f3b8ba79a"
Pragma:
- no-cache
Referrer-Policy:
- strict-origin-when-cross-origin
Transfer-Encoding:
- chunked
Vary:
- Accept, Origin
X-Content-Type-Options:
- nosniff
X-Download-Options:
- noopen
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Request-Id:
- 086350f4-00fc-4d82-a5ce-2b557df59682
X-Runtime:
- '0.040539'
X-XSS-Protection:
- 1; mode=block
status:
code: 200
message: OK
- request:
body: client_id=__MASTODON_PY_TEST_CLIENT_ID&client_secret=__MASTODON_PY_TEST_CLIENT_SECRET&token=s3ZSxpaa2Uhe9EcHankvkfaQZQGiWpdEWIhX7GuhDlk
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Authorization:
- Bearer s3ZSxpaa2Uhe9EcHankvkfaQZQGiWpdEWIhX7GuhDlk
Connection:
- keep-alive
Content-Length:
- '135'
Content-Type:
- application/x-www-form-urlencoded
User-Agent:
- tests/v311
method: POST
uri: http://localhost:3000/oauth/revoke
response:
body:
string: '{}'
headers:
Cache-Control:
- max-age=0, private, must-revalidate
Content-Security-Policy:
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
style-src ''self'' http://localhost:3000 ''nonce-PqM4ChK427oGZ5jIKprkYQ=='';
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
worker-src ''self'' blob: http://localhost:3000'
Content-Type:
- application/json; charset=utf-8
ETag:
- W/"44136fa355b3678a1146ad16f7e8649e"
Referrer-Policy:
- strict-origin-when-cross-origin
Transfer-Encoding:
- chunked
Vary:
- Accept
X-Content-Type-Options:
- nosniff
X-Download-Options:
- noopen
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Request-Id:
- 36ec7e63-b15b-487a-aa4a-c396db945794
X-Runtime:
- '0.010431'
X-XSS-Protection:
- 1; mode=block
status:
code: 200
message: OK
- request:
body: status=illegal+access+detected
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '30'
Content-Type:
- application/x-www-form-urlencoded
User-Agent:
- tests/v311
method: POST
uri: http://localhost:3000/api/v1/statuses
response:
body:
string: '{"error":"The access token is invalid"}'
headers:
Cache-Control:
- no-store
Content-Security-Policy:
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
style-src ''self'' http://localhost:3000 ''nonce-UClOh6+Y0zf3a4O/ysqT/w=='';
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
worker-src ''self'' blob: http://localhost:3000'
Content-Type:
- application/json; charset=utf-8
Pragma:
- no-cache
Referrer-Policy:
- strict-origin-when-cross-origin
Transfer-Encoding:
- chunked
Vary:
- Accept, Origin
WWW-Authenticate:
- Bearer realm="Doorkeeper", error="invalid_token", error_description="The access
token is invalid"
X-Content-Type-Options:
- nosniff
X-Download-Options:
- noopen
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Request-Id:
- ab1f9d04-149b-431a-b2b0-79921d45f3bc
X-Runtime:
- '0.005292'
X-XSS-Protection:
- 1; mode=block
status:
code: 401
message: Unauthorized
- request:
body: status=illegal+access+detected
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '30'
Content-Type:
- application/x-www-form-urlencoded
User-Agent:
- tests/v311
method: POST
uri: http://localhost:3000/api/v1/statuses
response:
body:
string: '{"error":"The access token is invalid"}'
headers:
Cache-Control:
- no-store
Content-Security-Policy:
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
style-src ''self'' http://localhost:3000 ''nonce-ZTmQUUs9q7lX74Aa3bTgzA=='';
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
worker-src ''self'' blob: http://localhost:3000'
Content-Type:
- application/json; charset=utf-8
Pragma:
- no-cache
Referrer-Policy:
- strict-origin-when-cross-origin
Transfer-Encoding:
- chunked
Vary:
- Accept, Origin
WWW-Authenticate:
- Bearer realm="Doorkeeper", error="invalid_token", error_description="The access
token is invalid"
X-Content-Type-Options:
- nosniff
X-Download-Options:
- noopen
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Request-Id:
- 9a7ad262-0d94-4df6-92a5-a670d6515979
X-Runtime:
- '0.004613'
X-XSS-Protection:
- 1; mode=block
status:
code: 401
message: Unauthorized
version: 1

Wyświetl plik

@ -22,14 +22,37 @@ def test_log_in_none(api_anonymous):
with pytest.raises(MastodonIllegalArgumentError):
api_anonymous.log_in()
@pytest.mark.vcr()
def test_log_in_password(api_anonymous):
token = api_anonymous.log_in(
username='mastodonpy_test_2@localhost:3000',
password='5fc638e0e53eafd9c4145b6bb852667d')
password='5fc638e0e53eafd9c4145b6bb852667d'
)
assert token
@pytest.mark.vcr()
def test_revoke(api_anonymous):
token = api_anonymous.log_in(
username='mastodonpy_test_2@localhost:3000',
password='5fc638e0e53eafd9c4145b6bb852667d'
)
api_anonymous.revoke_access_token()
try:
api_anonymous.toot("illegal access detected")
assert False
except Exception as e:
print(e)
pass
api_revoked_token = Mastodon(access_token = token)
try:
api_anonymous.toot("illegal access detected")
assert False
except Exception as e:
print(e)
pass
@pytest.mark.vcr()
def test_log_in_password_incorrect(api_anonymous):
with pytest.raises(MastodonIllegalArgumentError):