def post(self, request, *args, **kwargs): grant_type = request.POST.get('grant_type', 'password') username = request.POST.get('username') # pre-validate scopes requested client_id = request.POST.get('client_id', None) requested_scopes = [s for s in scope_to_list(request.POST.get('scope', '')) if s] if client_id: try: oauth_app = Application.objects.get(client_id=client_id) except Application.DoesNotExist: return HttpResponse(json.dumps({"error": "invalid client_id"}), status=HTTP_400_BAD_REQUEST) try: allowed_scopes = oauth_app.applicationinfo.scope_list except ApplicationInfo.DoesNotExist: allowed_scopes = ['r:profile'] # handle rw:issuer:* scopes if 'rw:issuer:*' in allowed_scopes: issuer_scopes = filter(lambda x: x.startswith(r'rw:issuer:'), requested_scopes) allowed_scopes.extend(issuer_scopes) filtered_scopes = set(allowed_scopes) & set(requested_scopes) if len(filtered_scopes) < len(requested_scopes): return HttpResponse(json.dumps({"error": "invalid scope requested"}), status=HTTP_400_BAD_REQUEST) # let parent method do actual authentication response = super(TokenView, self).post(request, *args, **kwargs) if grant_type == "password" and response.status_code == 401: badgrlogger.event(badgrlog.FailedLoginAttempt(request, username, endpoint='/o/token')) return response
def login(self, request, extra_context=None): response = super(BadgrAdminSite, self).login(request, extra_context) if request.method == 'POST': # form submission if response.status_code != 302: # failed /staff login username = request.POST.get('username', None) badgrlogger.event(badgrlog.FailedLoginAttempt(request, username, endpoint='/staff/login')) return response
def post(self, request, *args, **kwargs): def _request_identity(request): username = request.POST.get('username', None) if username: return username return client_ip_from_request(self.request) def _backoff_cache_key(request): return "failed_token_backoff_{}".format(_request_identity(request)) _backoff_period = getattr(settings, 'TOKEN_BACKOFF_PERIOD_SECONDS', 2) grant_type = request.POST.get('grant_type', 'password') if grant_type == 'password' and _backoff_period is not None: # check for existing backoff for password attempts backoff = cache.get(_backoff_cache_key(request)) if backoff is not None: backoff_until = backoff.get('until', None) backoff_count = backoff.get('count', 1) if backoff_until > timezone.now(): backoff_count += 1 backoff_seconds = min( 86400, _backoff_period** backoff_count) # maximum backoff is 24 hours backoff_until = timezone.now() + datetime.timedelta( seconds=backoff_seconds) cache.set(_backoff_cache_key(request), dict(until=backoff_until, count=backoff_count), timeout=None) # return the same error as a failed login attempt return HttpResponse(json.dumps({ "error_description": "Invalid credentials given.", "error": "invalid_grant" }), status=HTTP_401_UNAUTHORIZED) # pre-validate scopes requested client_id = request.POST.get('client_id', None) requested_scopes = [ s for s in scope_to_list(request.POST.get('scope', '')) if s ] if client_id: try: oauth_app = Application.objects.get(client_id=client_id) except Application.DoesNotExist: return HttpResponse(json.dumps({"error": "invalid client_id"}), status=HTTP_400_BAD_REQUEST) try: allowed_scopes = oauth_app.applicationinfo.scope_list except ApplicationInfo.DoesNotExist: allowed_scopes = ['r:profile'] # handle rw:issuer:* scopes if 'rw:issuer:*' in allowed_scopes: issuer_scopes = [ x for x in requested_scopes if x.startswith(r'rw:issuer:') ] allowed_scopes.extend(issuer_scopes) filtered_scopes = set(allowed_scopes) & set(requested_scopes) if len(filtered_scopes) < len(requested_scopes): return HttpResponse(json.dumps( {"error": "invalid scope requested"}), status=HTTP_400_BAD_REQUEST) # let parent method do actual authentication response = super(TokenView, self).post(request, *args, **kwargs) if grant_type == "password" and response.status_code == 401: # failed password login attempt username = request.POST.get('username', None) badgrlogger.event( badgrlog.FailedLoginAttempt(request, username, endpoint='/o/token')) if _backoff_period is not None: # update backoff for failed logins backoff = cache.get(_backoff_cache_key(request)) if backoff is None: backoff = {'count': 0} backoff['count'] += 1 backoff['until'] = timezone.now() + datetime.timedelta( seconds=_backoff_period**backoff['count']) cache.set(_backoff_cache_key(request), backoff, timeout=None) elif response.status_code == 200: # successful login cache.set(_backoff_cache_key(request), None) # clear any existing backoff return response
def post(self, request, *args, **kwargs): if len(request.GET): return HttpResponse(json.dumps({ "error": "Token grant parameters must be sent in post body, not query parameters" }), status=HTTP_400_BAD_REQUEST) grant_type = request.POST.get('grant_type', 'password') username = request.POST.get('username') client_id = None try: auth_header = request.META['HTTP_AUTHORIZATION'] credentials = auth_header.split(' ') if credentials[0] == 'Basic': client_id, client_secret = base64.b64decode( credentials[1].encode('ascii')).decode('ascii').split(':') except (KeyError, IndexError, ValueError, TypeError): client_id = request.POST.get('client_id', None) client_secret = None # pre-validate scopes requested requested_scopes = [ s for s in scope_to_list(request.POST.get('scope', '')) if s ] oauth_app = None if client_id: try: oauth_app = Application.objects.get(client_id=client_id) if client_secret and oauth_app.client_secret != client_secret: return HttpResponse(json.dumps( {"error": "invalid client_secret"}), status=HTTP_400_BAD_REQUEST) except Application.DoesNotExist: return HttpResponse(json.dumps({"error": "invalid client_id"}), status=HTTP_400_BAD_REQUEST) try: allowed_scopes = oauth_app.applicationinfo.scope_list except ApplicationInfo.DoesNotExist: allowed_scopes = ['r:profile'] # handle rw:issuer:* scopes if 'rw:issuer:*' in allowed_scopes: issuer_scopes = [ x for x in requested_scopes if x.startswith(r'rw:issuer:') ] allowed_scopes.extend(issuer_scopes) filtered_scopes = set(allowed_scopes) & set(requested_scopes) if len(filtered_scopes) < len(requested_scopes): return HttpResponse(json.dumps( {"error": "invalid scope requested"}), status=HTTP_400_BAD_REQUEST) # let parent method do actual authentication response = super(TokenView, self).post(request, *args, **kwargs) if oauth_app and not oauth_app.applicationinfo.issue_refresh_token: data = json.loads(response.content) try: del data['refresh_token'] except KeyError: pass response.content = json.dumps(data) if grant_type == "password" and response.status_code == 401: badgrlogger.event( badgrlog.FailedLoginAttempt(request, username, endpoint='/o/token')) return response