Skip to content

Commit df8f3ee

Browse files
committed
oauth: Add logging on failures
1 parent 23bc280 commit df8f3ee

File tree

2 files changed

+62
-17
lines changed

2 files changed

+62
-17
lines changed

src/sentry/web/frontend/oauth_authorize.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import absolute_import, print_function
22

3+
import logging
34
import six
45

56
from django.conf import settings
@@ -13,6 +14,8 @@
1314
)
1415
from sentry.web.frontend.auth_login import AuthLoginView
1516

17+
logger = logging.getLogger('sentry.api')
18+
1619

1720
class OAuthAuthorizeView(AuthLoginView):
1821
auth_required = False
@@ -37,7 +40,13 @@ def redirect_response(self, response_type, redirect_uri, params):
3740
parts[4] = urlencode(query)
3841
return self.redirect(urlunparse(parts))
3942

40-
def error(self, response_type, redirect_uri, name, state=None):
43+
def error(self, request, response_type, redirect_uri, name, state=None, client_id=None):
44+
logging.error('oauth.authorize-error', extra={
45+
'error_name': name,
46+
'response_type': response_type,
47+
'client_id': client_id,
48+
'redirect_uri': redirect_uri,
49+
})
4150
return self.redirect_response(
4251
response_type, redirect_uri, {
4352
'error': name,
@@ -58,6 +67,12 @@ def get(self, request):
5867
force_prompt = request.GET.get('force_prompt')
5968

6069
if not client_id:
70+
logging.error('oauth.authorize-error', extra={
71+
'error_name': 'unauthorized_client',
72+
'response_type': response_type,
73+
'client_id': client_id,
74+
'redirect_uri': redirect_uri,
75+
})
6176
return self.respond(
6277
'sentry/oauth-error.html', {
6378
'error': mark_safe('Missing or invalid <em>client_id</em> parameter.'),
@@ -70,6 +85,12 @@ def get(self, request):
7085
status=ApiApplicationStatus.active,
7186
)
7287
except ApiApplication.DoesNotExist:
88+
logging.error('oauth.authorize-error', extra={
89+
'error_name': 'unauthorized_client',
90+
'response_type': response_type,
91+
'client_id': client_id,
92+
'redirect_uri': redirect_uri,
93+
})
7394
return self.respond(
7495
'sentry/oauth-error.html', {
7596
'error': mark_safe('Missing or invalid <em>client_id</em> parameter.'),
@@ -79,6 +100,12 @@ def get(self, request):
79100
if not redirect_uri:
80101
redirect_uri = application.get_default_redirect_uri()
81102
elif not application.is_valid_redirect_uri(redirect_uri):
103+
logging.error('oauth.authorize-error', extra={
104+
'error_name': 'invalid_request',
105+
'response_type': response_type,
106+
'client_id': client_id,
107+
'redirect_uri': redirect_uri,
108+
})
82109
return self.respond(
83110
'sentry/oauth-error.html', {
84111
'error': mark_safe('Missing or invalid <em>redirect_uri</em> parameter.'),
@@ -87,6 +114,8 @@ def get(self, request):
87114

88115
if not application.is_allowed_response_type(response_type):
89116
return self.error(
117+
request=request,
118+
client_id=client_id,
90119
response_type=response_type,
91120
redirect_uri=redirect_uri,
92121
name='unsupported_response_type',
@@ -98,6 +127,8 @@ def get(self, request):
98127
for scope in scopes:
99128
if scope not in settings.SENTRY_SCOPES:
100129
return self.error(
130+
request=request,
131+
client_id=client_id,
101132
response_type=response_type,
102133
redirect_uri=redirect_uri,
103134
name='invalid_scope',
@@ -232,6 +263,8 @@ def post(self, request):
232263

233264
elif op == 'deny':
234265
return self.error(
266+
request=request,
267+
client_id=payload['cid'],
235268
response_type=response_type,
236269
redirect_uri=redirect_uri,
237270
name='access_denied',

src/sentry/web/frontend/oauth_token.py

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import absolute_import, print_function
22

3+
import logging
34
import six
45

56
from django.http import HttpResponse
@@ -12,14 +13,25 @@
1213
from sentry.models import (ApiApplication, ApiApplicationStatus, ApiGrant, ApiToken)
1314
from sentry.utils import json
1415

16+
logger = logging.getLogger('sentry.api')
17+
1518

1619
class OAuthTokenView(View):
1720
@csrf_exempt
1821
@never_cache
1922
def dispatch(self, request, *args, **kwargs):
2023
return super(OAuthTokenView, self).dispatch(request, *args, **kwargs)
2124

22-
def error(self, name, status=400):
25+
def error(self, request, name, status=400):
26+
client_id = request.POST.get('client_id')
27+
redirect_uri = request.POST.get('redirect_uri')
28+
29+
logging.error('oauth.token-error', extra={
30+
'error_name': name,
31+
'status': status,
32+
'client_id': client_id,
33+
'redirect_uri': redirect_uri,
34+
})
2335
return HttpResponse(
2436
json.dumps({
2537
'error': name,
@@ -37,34 +49,34 @@ def post(self, request):
3749
code = request.POST.get('code')
3850

3951
if not client_id:
40-
return self.error('invalid_client')
52+
return self.error(request, 'invalid_client')
4153

4254
if not client_secret:
43-
return self.error('invalid_client')
55+
return self.error(request, 'invalid_client')
4456

4557
try:
4658
application = ApiApplication.objects.get(
4759
client_id=client_id,
4860
status=ApiApplicationStatus.active,
4961
)
5062
except ApiApplication.DoesNotExist:
51-
return self.error('invalid_client')
63+
return self.error(request, 'invalid_client')
5264

5365
if not constant_time_compare(client_secret, application.client_secret):
54-
return self.error('invalid_client')
66+
return self.error(request, 'invalid_client')
5567

5668
try:
5769
grant = ApiGrant.objects.get(application=application, code=code)
5870
except ApiGrant.DoesNotExist:
59-
return self.error('invalid_grant')
71+
return self.error(request, 'invalid_grant')
6072

6173
if grant.is_expired():
62-
return self.error('invalid_grant')
74+
return self.error(request, 'invalid_grant')
6375

6476
if not redirect_uri:
6577
redirect_uri = application.get_default_redirect_uri()
6678
elif grant.redirect_uri != redirect_uri:
67-
return self.error('invalid_grant')
79+
return self.error(request, 'invalid_grant')
6880

6981
token = ApiToken.from_grant(grant)
7082
elif grant_type == 'refresh_token':
@@ -74,40 +86,40 @@ def post(self, request):
7486
client_secret = request.POST.get('client_secret')
7587

7688
if not refresh_token:
77-
return self.error('invalid_request')
89+
return self.error(request, 'invalid_request')
7890

7991
# TODO(dcramer): support scope
8092
if scope:
81-
return self.error('invalid_request')
93+
return self.error(request, 'invalid_request')
8294

8395
if not client_id:
84-
return self.error('invalid_client')
96+
return self.error(request, 'invalid_client')
8597

8698
if not client_secret:
87-
return self.error('invalid_client')
99+
return self.error(request, 'invalid_client')
88100

89101
try:
90102
application = ApiApplication.objects.get(
91103
client_id=client_id,
92104
status=ApiApplicationStatus.active,
93105
)
94106
except ApiApplication.DoesNotExist:
95-
return self.error('invalid_client')
107+
return self.error(request, 'invalid_client')
96108

97109
if not constant_time_compare(client_secret, application.client_secret):
98-
return self.error('invalid_client')
110+
return self.error(request, 'invalid_client')
99111

100112
try:
101113
token = ApiToken.objects.get(
102114
application=application,
103115
refresh_token=refresh_token,
104116
)
105117
except ApiToken.DoesNotExist:
106-
return self.error('invalid_grant')
118+
return self.error(request, 'invalid_grant')
107119

108120
token.refresh()
109121
else:
110-
return self.error('unsupported_grant_type')
122+
return self.error(request, 'unsupported_grant_type')
111123

112124
return HttpResponse(
113125
json.dumps(

0 commit comments

Comments
 (0)