def post(self, request): form = Auth2faForm.Basic.create_from_request(request) if not request.token: raise ApiException(request, _('User is unauthorized.'), status_code=HTTPStatus.FORBIDDEN) if not form.is_valid(): raise ValidationException(request, form) code = form.cleaned_data.get('code') user = request.user token = request.token if user.is_2fa: totp = pyotp.TOTP(user.additional_data.get('otp_secret')) totp.now() if totp.verify(code): token.active_2fa = True token.save() else: raise ApiException(request, _('Invalid or missing credentials'), status_code=HTTPStatus.UNAUTHORIZED) else: raise ApiException(request, _('User is unauthorized.'), status_code=HTTPStatus.FORBIDDEN) return SingleResponse(request, token, status=HTTPStatus.OK, serializer=TokenSerializer.Base)
def put(self, request, service_id): try: service = Service.objects.get(pk=service_id) except Service.DoesNotExist: raise ApiException(request, _('Service does not exist.'), status_code=HTTPStatus.NOT_FOUND) form = ServiceForms.Basic.create_from_request(request) if not form.is_valid(): raise ValidationException(request, form) if service.name != form.cleaned_data['name']: if form.cleaned_data['remote_id'].services.filter(name=form.cleaned_data['name']).exists(): raise ApiException( request=request, message=_('Assigned remote already has service with name: "{service_name}"').format( service_name=form.cleaned_data['name'] ), status_code=HTTPStatus.CONFLICT ) form.fill(service) service.save() return SingleResponse(request, data=service, status=HTTPStatus.OK, serializer=ServiceSerializer.Base)
def put(self, request, remote_id): try: remote = Remote.objects.get(pk=remote_id) except Remote.DoesNotExist: raise ApiException(request, _('Remote does not exist.'), status_code=HTTPStatus.NOT_FOUND) form = RemoteForms.Basic.create_from_request(request) if not form.is_valid(): raise ValidationException(request, form) if remote.name != form.cleaned_data['name']: if form.cleaned_data['project_id'].remotes.filter(name=form.cleaned_data['name']).exists(): raise ApiException( request=request, message=_('Assigned project already has remote with name: "{remote_name}"').format( remote_name=form.cleaned_data['name'] ), status_code=HTTPStatus.CONFLICT ) form.fill(remote) remote.save() return SingleResponse(request, data=remote, status=HTTPStatus.OK, serializer=RemoteSerializer.Base)
def get(self, request, remote_id): try: remote = Remote.objects.get(pk=remote_id) except Remote.DoesNotExist: raise ApiException(request, _('Remote does not exist.'), status_code=HTTPStatus.NOT_FOUND) if not has_object_permission('check_remote', request.user, remote): raise ApiException(request, _('User is unauthorized.'), status_code=HTTPStatus.FORBIDDEN) return SingleResponse(request, remote, serializer=RemoteSerializer.Base)
def inner(request, *args, **kwargs): if not hasattr( request, 'user' ) or not request.user or not request.user.is_authenticated: raise ApiException(request, _("Invalid or missing credentials"), status_code=HTTPStatus.UNAUTHORIZED) elif request.user.is_2fa and not request.token.active_2fa: raise ApiException(request, _("Invalid or missing credentials"), status_code=HTTPStatus.UNAUTHORIZED) return func(request, *args, **kwargs)
def __call__(self, request): auth_header = request.headers.get('Authorization', b'').split() if not auth_header: return self.get_response(request) if len(auth_header) != 2: return ErrorResponse.create_from_exception( ApiException(request, _("Improperly formatted token"), status_code=HTTPStatus.BAD_REQUEST) ) try: Token.objects.filter(expires_at__lt=timezone.now()).hard_delete() except AttributeError: pass try: user = auth.authenticate(request, token=auth_header[1]) except ApiException: user = None if user: request.user = user request.token = user.tokens.get(pk=auth_header[1]) return self.get_response(request)
def get(self, request, service_id): try: service = Service.objects.get(pk=service_id) except Service.DoesNotExist: raise ApiException(request, _('Service does not exist.'), status_code=HTTPStatus.NOT_FOUND) return SingleResponse(request, service, serializer=ServiceSerializer.Base)
def get(self, request, project_id): try: project = Project.objects.get(pk=project_id) except Project.DoesNotExist: raise ApiException(request, _('Project does not exist.'), status_code=HTTPStatus.NOT_FOUND) if not has_object_permission('check_project', request.user, project): raise ApiException(request, _('User is unauthorized.'), status_code=HTTPStatus.FORBIDDEN) return SingleResponse(request, project, serializer=ProjectSerializer.Detail)
def _function(request, *args, **kwargs): if request.user.has_perm(perm): return function(request, *args, **kwargs) else: raise ApiException(request, _('Permission denied.'), status_code=HTTPStatus.FORBIDDEN)
def inner(request, *args, **kwargs): if not request.user.is_authenticated or not request.user.is_superuser: raise ApiException(request, _('User is unauthorized.'), status_code=HTTPStatus.FORBIDDEN) return func(request, *args, **kwargs)
def delete(self, request, service_id): try: service = Service.objects.get(pk=service_id) except Service.DoesNotExist: raise ApiException(request, _('Service does not exist.'), status_code=HTTPStatus.NOT_FOUND) service.delete() return HttpResponse(status=HTTPStatus.NO_CONTENT)
def get(self, request, user_id): try: user = User.objects.get(pk=user_id) except User.DoesNotExist: raise ApiException(request, _('User does not exist.'), status_code=HTTPStatus.NOT_FOUND) return SingleResponse(request, user, serializer=UserSerializer.Detail)
def __init__(self, request: HttpRequest, variables: dict): self._request = request self._variables = variables if hasattr(self._request, 'api_key'): self._api_key = self._request.api_key else: raise ApiException(self._request, _('Request does not have any api_key.'), status_code=HTTPStatus.NOT_FOUND)
def delete(self, request, remote_id): try: remote = Remote.objects.get(pk=remote_id) except Remote.DoesNotExist: raise ApiException(request, _('Remote does not exist.'), status_code=HTTPStatus.NOT_FOUND) remote.services.all().delete() remote.delete() return HttpResponse(status=HTTPStatus.NO_CONTENT)
def delete(self, request, api_key_id): try: api_key = ApiKey.objects.get(pk=api_key_id) except ApiKey.DoesNotExist: raise ApiException(request, _('Api key does not exist.'), status_code=HTTPStatus.NOT_FOUND) api_key.delete() return HttpResponse(status=HTTPStatus.NO_CONTENT)
def delete(self, request, user_id): try: user = User.objects.get(pk=user_id) except User.DoesNotExist: raise ApiException(request, _('User does not exist.'), status_code=HTTPStatus.NOT_FOUND) user.delete() return HttpResponse(status=HTTPStatus.NO_CONTENT)
def delete(self, request): user = request.user if user.is_temporary: user.delete() else: raise ApiException(request, _('Permission denied.'), status_code=HTTPStatus.FORBIDDEN) return HttpResponse(status=HTTPStatus.NO_CONTENT)
def get(self, request, api_key_id): try: api_key = ApiKey.objects.get(pk=api_key_id) except ApiKey.DoesNotExist: raise ApiException(request, _('Api key does not exist.'), status_code=HTTPStatus.NOT_FOUND) return SingleResponse(request, api_key, serializer=ApiKeySerializer.Base)
def process_view(request, view_func, view_args, view_kwargs): # View functions if hasattr(view_func, 'signature_exempt') and view_func.signature_exempt: return None # View classes if hasattr(view_func, 'view_class') \ and hasattr(view_func.view_class, 'skip_signature') \ and request.method.lower() in view_func.view_class.skip_signature: return None api_key = request.headers.get('X-Apikey') signature = request.headers.get('X-Signature', '') try: api_key_model = ApiKey.objects.get(key=api_key, is_active=True) except ApiKey.DoesNotExist: return ErrorResponse.create_from_exception( ApiException(request, _('Invalid api key.'))) request.api_key = api_key_model # # Do not check signature for GitLab API keys # if api_key_model.platform == ApiKey.ApiKeyType.GIT: # return None # # message = f"{request.body.decode('utf-8')}:{request.path}" # signature_check = hmac.new( # api_key_model.secret.encode('utf-8'), # msg=message.encode('utf-8'), # digestmod=hashlib.sha256 # ).hexdigest() # # # Do not check signature for DEBUG API keys in DEBUG environment # if api_key_model.platform == ApiKey.ApiKeyType.DEBUG and settings.DEBUG: # return None # # if signature != signature_check: # return ErrorResponse.create_from_exception( # ApiException( # request, # _('Invalid signature.'), # HTTPStatus.FORBIDDEN, # to_sentry=True, # additional_data={ # 'received': signature, # 'expected': signature_check, # 'message': message, # } # ) # ) return None
def __call__(self, request): if request.user and not isinstance(request.user, AnonymousUser): logged_device = self._get_logged_device(request.user, request) if logged_device is not None: request.logged_device = logged_device else: raise ApiException( request, _('You are trying to connect from a unknown device.'), status_code=HTTPStatus.FORBIDDEN) return self.get_response(request)
def delete(self, request, project_id): try: project = Project.objects.get(pk=project_id) except Project.DoesNotExist: raise ApiException(request, _('Project does not exist.'), status_code=HTTPStatus.NOT_FOUND) for remote in project.remotes.all(): remote.services.all().delete() remote.delete() project.delete() return HttpResponse(status=HTTPStatus.NO_CONTENT)
def put(self, request, user_id): try: user = User.objects.get(pk=user_id) except User.DoesNotExist: raise ApiException(request, _('User does not exist.'), status_code=HTTPStatus.NOT_FOUND) form = UserForms.Update.create_from_request(request) if not form.is_valid(): raise ValidationException(request, form) email = form.cleaned_data.get('email') assign_projects = form.cleaned_data.get('assign_projects') role = form.cleaned_data.get('role') if email != user.email: if User.objects.filter(email=email).exists(): raise ApiException(request, _('Email is already used.'), status_code=HTTPStatus.CONFLICT) form.fill(user) user.username = email if assign_projects is not None: user.assign_projects(request, assign_projects) if role: clear_roles(user) assign_role(user, role.value) user.save() return SingleResponse(request, data=user, status=HTTPStatus.OK, serializer=UserSerializer.Base)
def assign_projects(self, request, projects_devices): self.projects_devices.all().delete() for project_devices in projects_devices: project = project_devices.get('project_id') devices = project_devices.get('devices') for device in devices: if device.user != self: raise ApiException( request, _('The device does not belong to specified user.'), status_code=HTTPStatus.CONFLICT) self.projects_devices.create(project=project, device=device)
def get(self, request, email): try: user = User.objects.get(email=email) except User.DoesNotExist: raise ApiException(request, _('User with specified email does not exist.'), status_code=HTTPStatus.NOT_FOUND) timestamp = int(datetime.utcnow().timestamp()) ts_b36 = int_to_base36(timestamp) login_timestamp = '' if user.last_login is None else user.last_login.replace( microsecond=0, tzinfo=None) hash_value = six.text_type(user.pk) + user.password + six.text_type( login_timestamp) + six.text_type(timestamp) recovery_hash = salted_hmac( settings.SECRET_KEY, hash_value, ).hexdigest()[::2] password_recovery = PasswordRecovery.objects.create( value="%s-%s" % (ts_b36, recovery_hash), user=user, expires_at=timezone.now() + settings.PASSWORD_RECOVERY_TIME) recovery_url = f'{settings.BASE_URL}/password/activate/{password_recovery.value}' NotificationService.create( recipients=[user.email], sender=f"{settings.EMAIL_SENDER_NAME} <{settings.EMAIL_SENDER}>", subject=_('[Praetorian API] - Email recovery'), content={ 'message': _('test'), 'recovery_url': recovery_url, 'email_text': _('Your recovery link to Praetorian API is: ') }, template='_emails/password_recovery.html').send_email() return SingleResponse(request, password_recovery, status=HTTPStatus.CREATED, serializer=PasswordRecoverySerializer.Base)
def post(self, request): form = ServiceForms.Basic.create_from_request(request) if not form.is_valid(): raise ValidationException(request, form) if form.cleaned_data['remote_id'].services.filter(name=form.cleaned_data['name']).exists(): raise ApiException( request=request, message=_('Assigned remote already has service with name: "{service_name}"').format( service_name=form.cleaned_data['name'] ), status_code=HTTPStatus.CONFLICT ) service = Service() form.fill(service) service.save() return SingleResponse(request, service, status=HTTPStatus.CREATED, serializer=ServiceSerializer.Base)
def put(self, request, project_id): try: project = Project.objects.get(pk=project_id) except Project.DoesNotExist: raise ApiException(request, _('Project does not exist.'), status_code=HTTPStatus.NOT_FOUND) form = ProjectForms.Basic.create_from_request(request) if not form.is_valid(): raise ValidationException(request, form) form.fill(project) project.save() return SingleResponse(request, data=project, status=HTTPStatus.OK, serializer=ProjectSerializer.Detail)
def put(self, request, api_key_id): try: api_key = ApiKey.objects.get(pk=api_key_id) except ApiKey.DoesNotExist: raise ApiException(request, _('Api key does not exist.'), status_code=HTTPStatus.NOT_FOUND) form = ApiKeyForms.Basic.create_from_request(request) if not form.is_valid(): raise ValidationException(request, form) form.fill(api_key) api_key.save() return SingleResponse(request, data=api_key, status=HTTPStatus.OK, serializer=ApiKeySerializer.Base)
def post(self, request): form = RemoteForms.Basic.create_from_request(request) if not form.is_valid(): raise ValidationException(request, form) if form.cleaned_data['project_id'].remotes.filter(name=form.cleaned_data['name']).exists(): raise ApiException( request=request, message=_('Assigned project already has remote with name: "{remote_name}"').format( remote_name=form.cleaned_data['name'] ), status_code=HTTPStatus.CONFLICT ) remote = Remote() form.fill(remote) remote.variables = {} remote.save() return SingleResponse(request, remote, status=HTTPStatus.CREATED, serializer=RemoteSerializer.Base)
def post(self, request): form = PasswordActivateForm.create_from_request(request) if not form.is_valid(): raise ValidationException(request, form) request_data = form.cleaned_data try: password_recovery = PasswordRecovery.objects.get( value=request_data.get('hashed_recovery'), expires_at__gt=timezone.now()) except PasswordRecovery.DoesNotExist: raise ApiException(request, _('Password recovery does not exist.'), status_code=HTTPStatus.NOT_FOUND) password_recovery.user.set_password(request_data.get('password')) password_recovery.user.save() PasswordRecovery.objects.filter(user=password_recovery.user).delete() return SingleResponse(request, None, status=HTTPStatus.NO_CONTENT)
def get(self, request, user_id): try: user = User.objects.get(pk=user_id) except User.DoesNotExist: raise ApiException(request, _('User does not exist.'), status_code=HTTPStatus.NOT_FOUND) otp_secret = pyotp.random_base32() qr_code_url = pyotp.totp.TOTP(otp_secret).provisioning_uri( name=user.email, issuer_name="Praetorian API") response = {'qr_code': qr_code_url} if user.additional_data: user.additional_data['otp_secret'] = otp_secret else: user.additional_data = {'otp_secret': otp_secret} user.is_2fa = True user.save() NotificationService.create( recipients=[user.email], sender=f"{settings.EMAIL_SENDER_NAME} <{settings.EMAIL_SENDER}>", subject=_('[Praetorian API] - Two factor authentication'), content={ 'message': _('test'), 'qr_code_url': self.make_qr_code(qr_code_url), 'email_text': _('QR code to activate your two factor authentication.') }, template='_emails/2fa_activation.html').send_email() return SingleResponse(request, response, status=HTTPStatus.CREATED, serializer=UserSerializer.Base)