def validate(self): if not self.authenticated: raise AccessDeniedError("Credentials token missing") from None elif 'expire' in self._credentials: utc_expire = utc(self._credentials['expire']) if now() > utc_expire: self.clear() raise AccessDeniedError('Credentials token expired') from None
def validate_access(req, obj_dict): if ('domain' in obj_dict and req.credentials.domain and req.credentials.domain != obj_dict['domain']): raise AccessDeniedError('object not in context domain "%s"' % req.credentials.domain) if ('tenant_id' in obj_dict and req.credentials.tenant_id and (req.credentials.tenant_id != obj_dict['tenant_id'] and req.credentials.tenant_id != obj_dict['id'])): raise AccessDeniedError('object not in context tenant "%s"' % req.credentials.tenant_id) return True
def json(self): # Return json token. if not self.authenticated: raise AccessDeniedError("Credentials token missing") utc_expire = utc(self._credentials['expire']) if now() > utc_expire: raise AccessDeniedError('Auth Token Expired') credentials = {} credentials['token'] = self.token credentials.update(self._credentials) return js.dumps(credentials)
def check_context_auth(conn, user_id, domain, tenant_id): """Verify if users has jurisdiction over requested domain/tenant. The default Root user can assign any role to any user. Only users with Admin or Root roles are allowed to assign roles to users. This function will raise an error if the requesting user is not an admin user on the requested domain/tenant. Args: conn (obj): DB connection object. user_id (str): UUID of user. domain (str): Name of the domain. tenant_id (str): UUID of the tenant. """ req_user_id = g.current_request.token.user_id if req_user_id != '00000000-0000-0000-0000-000000000000': cur = conn.execute("SELECT id FROM luxon_role WHERE name=?", ('Administrator', )) admin_id = cur.fetchone()['id'] query, vals = build_where(user_id=req_user_id, domain=domain, tenant_id=tenant_id) query += " AND ('role_id'='00000000-0000-0000-0000-000000000000'" query += " OR role_id=?)" vals.append(admin_id) sql = "SELECT id FROM luxon_user_role WHERE " + query cur = conn.execute(sql, vals) if not cur.fetchone(): raise AccessDeniedError( "User %s not authorized in requested context " ": domain '%s', tenant_id '%s'" % (req_user_id, domain, tenant_id))
def token(self, token): # Load exisiting token token = if_unicode_to_bytes(token) signature, b64_token = token.split(b'!!!!') try: self._rsakey.verify(signature, b64_token) except ValueError as e: raise AccessDeniedError('Invalid Auth Token. %s' % e) decoded = js.loads(base64.b64decode(b64_token)) utc_expire = utc(decoded['expire']) if now() > utc_expire: raise AccessDeniedError('Auth Token Expired') self._credentials = decoded
def domain(self, value): self.validate() if ('domain' in self._credentials and self._credentials['domain'] is not None): if self._credentials['domain'] != value: raise AccessDeniedError("Token already scoped in 'domain'") self._credentials['domain'] = value
def tenant_id(self, value): self.validate() if ('tenant_id' in self._credentials and self._credentials['tenant_id'] is not None): if self._credentials['tenant_id'] != value: raise AccessDeniedError("Token already scoped in 'tenant'") self._credentials['tenant_id'] = value
def token(self): # Return serialized token. if not self.authenticated: raise AccessDeniedError("Credentials token missing") utc_expire = utc(self._credentials['expire']) if now() > utc_expire: raise AccessDeniedError('Auth Token Expired') bytes_token = if_unicode_to_bytes( js.dumps(self._credentials, indent=None)) b64_token = base64.b64encode(bytes_token) token_sig = if_unicode_to_bytes(self._rsakey.sign(b64_token)) token = if_bytes_to_unicode(token_sig + b'!!!!' + b64_token) if len(token) > 1280: raise ValueError("Auth Token exceeded 10KB" + " - Revise Assignments for credentials") return token
def password(self, username, domain, credentials): try: password = credentials['password'] except KeyError: raise ValueError("No 'password' provided in 'credentials'") if domain is None and username == 'root' and password == 'password': return True else: raise AccessDeniedError('Invalid credentials provided')
def validate_set_scope(req, obj_dict): if 'domain' in obj_dict: if (req.credentials.domain == req.context_domain or req.credentials.domain is None): if obj_dict['domain'] is None: if req.context_domain is not None: obj_dict.update({"domain": req.context_domain}) else: raise AccessDeniedError("Token not scoped for domain '%s'" % req.context_domain) if 'tenant_id' in obj_dict: if (req.credentials.tenant_id == req.context_tenant_id or req.credentials.tenant_id is None): if obj_dict['tenant_id'] is None: if req.context_tenant_id is not None: obj_dict.update({"tenant_id": req.context_tenant_id}) else: raise AccessDeniedError("Token not scoped for Tenant '%s'" % req.context_tenant_id)
def __setattr__(self, attr, value): if attr in self.__slots__: return object.__setattr__(self, attr, value) try: return object.__setattr__(self, attr, value) except AttributeError: self.validate() if (attr in self._credentials and self._credentials[attr] is not None): raise AccessDeniedError("Token scope '%s'" % attr + " not allowed") from None self._credentials[attr] = value
def auth(username, password): github = GitHub(( username, password, )) teams = github.teams('TachyonicProject') roles = [] for team in teams: id = team['id'] role = team['name'] members = github.team_members(id) for member in members: if member['login'] == username: roles.append(role) if len(roles) == 0: raise AccessDeniedError('Not member of any Tachyonic Project teams') return roles
def authorize(tag, username=None, password=None, domain=None): with db() as conn: values = [ tag, username, ] sql = 'SELECT username, password FROM luxon_user' sql += ' WHERE' sql += ' tag = %s' sql += ' AND username = %s' if domain is not None: sql += ' AND domain = %s' values.append(domain) else: sql += ' AND domain IS NULL' crsr = conn.execute(sql, values) result = crsr.fetchone() if result is not None: # Validate Password againts stored HASHED Value. if is_valid_password(password, result['password']): return True raise AccessDeniedError('Invalid credentials provided')
def proc(self, method, route): try: with Timer() as elapsed: # Request Object. request = g.current_request = Request(method, route) # Response Object. response = Response() # Set Response object for request. request.response = response # Debug output if g.app.debug is True: log.info('Request %s' % request.route + ' Method %s\n' % request.method) # Process the middleware 'pre' method before routing it for middleware in register._middleware_pre: middleware(request, response) # Route Object. resource, method, r_kwargs, target, tag, cache = router.find( request.method, request.route) # Route Kwargs in requests. request.route_kwargs = r_kwargs # Set route tag in requests. request.tag = tag # If route tagged validate with policy if tag is not None: if not request.policy.validate(tag): raise AccessDeniedError("Access Denied by" + " policy '%s'" % tag) # Execute Routed View. try: # Process the middleware 'resource' after routing it for middleware in register._middleware_resource: middleware(request, response) # Run View method. if resource is not None: view = resource(request, response, **r_kwargs) if view is not None: response.write(view) else: raise NotFoundError("Route not found" + " Method '%s'" % request.method + " Route '%s'" % request.route) finally: # Process the middleware 'post' at the end for middleware in register._middleware_post: middleware(request, response) except KeyboardInterrupt: response.write('CTRL-C / KeyboardInterrupt') except Exception as exception: trace = str(traceback.format_exc()) self.handle_error(request, response, exception, trace) # Return response object. finally: # Completed Request log.info('Completed CMD', timer=elapsed())
def __call__(self, *args, **kwargs): """Application Request Interface. A clean request and response object is provided to the interface that is unique this to this thread. It passes any args and kwargs to the interface. Response object is returned. """ try: with Timer() as elapsed: # Request Object. request = g.current_request = Request(*args, **kwargs) request.env['SCRIPT_NAME'] = g.app.config.get( 'application', 'script', fallback=request.env['SCRIPT_NAME']) script_name = request.get_header('X-Script-Name') if script_name: request.env['SCRIPT_NAME'] = script_name # Response Object. response = Response(*args, **kwargs) # Set Response object for request. request.response = response # Debug output if g.app.debug is True: log.info('Request %s' % request.route + ' Method %s\n' % request.method) # Process the middleware 'pre' method before routing it for middleware in register._middleware_pre: middleware(request, response) # Route Object. resource, method, r_kwargs, target, tag, cache = router.find( request.method, request.route) # Route Kwargs in requests. request.route_kwargs = r_kwargs # Set route tag in requests. request.tag = tag # If route tagged validate with policy if tag is not None: if not request.policy.validate(tag, access_denied_raise=True): raise AccessDeniedError("Access Denied by" + " policy '%s'" % tag) # Execute Routed View. try: # Process the middleware 'resource' after routing it for middleware in register._middleware_resource: middleware(request, response) # Run View method. if resource is not None: view = resource(request, response, **r_kwargs) if view is not None: response.body(view) else: raise NotFoundError("Route not found" + " Method '%s'" % request.method + " Route '%s'" % request.route) finally: # Process the middleware 'post' at the end self.post_middleware(request, response, False) # Cache GET Response. # Only cache for GET responses! if cache > 0 and request.method == 'GET': # Get session_id if any for Caching session_id = request.cookies.get(request.host) # NOTE(cfrademan): Instruct to use cache but revalidate on, # stale cache entry. Expire remote cache in same duration # as internal cache. if session_id: response.set_header( "cache-control", "must-revalidate, private, max-age=" + str(cache)) else: response.set_header( "cache-control", "must-revalidate, max-age=" + str(cache)) # Set Vary Header # NOTE(cfrademan): Client should uniquely cache # based these request headers. response.set_header( 'Vary', 'Cookie, Accept-Encoding' + ', Content-Type') # Set Etag # NOTE(cfrademan): Needed Encoding for Different Etag. if isinstance(response._stream, bytes): encoding = request.get_header('Accept-Encoding') response.etag.set(etagger(response._stream, encoding)) # If Etag matches do not return full body use # external/user-agent cache. if (len(request.if_none_match) > 0 and request.if_none_match in response.etag): # Etag matches do not return full body. response.not_modified() # NOTE(cfrademan): Use last_modified as last resort for # external/user-agent cache. elif (request.if_modified_since and response.last_modified and request.if_modified_since <= response.last_modified): # Last-Modified matches do not return full body. response.not_modified() else: response.set_header("cache-control", "no-store, no-cache, max-age=0") # Return response object. return response() except HTTPError as exception: trace = str(traceback.format_exc()) self.handle_error(request, response, exception, trace) self.post_middleware(request, response, True) # Return response object. return response() except Error as exception: trace = str(traceback.format_exc()) self.handle_error(request, response, exception, trace) self.post_middleware(request, response, True) # Return response object. return response() except Exception as exception: trace = str(traceback.format_exc()) self.handle_error(request, response, exception, trace) self.post_middleware(request, response, True) # Return response object. return response() finally: # Completed Request log.info('Completed Request', timer=elapsed())