Beispiel #1
0
async def do_traverse(request, parent, path):
    """Traverse for the code API."""
    if not path:
        return parent, path

    assert request is not None  # could be used for permissions, etc

    if IContainer.providedBy(parent) and \
       path[0] != request._db_id:
        # Tried to access a container outside the request
        raise HTTPUnauthorized()

    if IApplication.providedBy(parent) and \
       path[0] != request._container_id:
        # Tried to access a container outside the request
        raise HTTPUnauthorized()

    try:
        if path[0].startswith('_') or path[0] in ('.', '..'):
            raise HTTPUnauthorized()
        context = parent[path[0]]
    except TypeError:
        return parent, path
    except KeyError:
        return parent, path

    context._v_parent = parent

    return await traverse(request, context, path[1:])
Beispiel #2
0
    async def token_validation(self, request, handler):
        """Check security access of this layer."""
        hassio_token = request.headers.get(HEADER_TOKEN)

        # Ignore security check
        for rule in NO_SECURITY_CHECK:
            if rule.match(request.path):
                _LOGGER.debug("Passthrough %s", request.path)
                return await handler(request)

        # Unknown API access
        if not hassio_token:
            _LOGGER.warning("Invalid token for access %s", request.path)
            raise HTTPUnauthorized()

        # Home-Assistant
        if hassio_token == self.sys_homeassistant.uuid:
            _LOGGER.debug("%s access from Home-Assistant", request.path)
            request[REQUEST_FROM] = 'homeassistant'

        # Host
        if hassio_token == self.sys_machine_id:
            _LOGGER.debug("%s access from Host", request.path)
            request[REQUEST_FROM] = 'host'

        # Add-on
        addon = self.sys_addons.from_uuid(hassio_token)
        if addon:
            _LOGGER.info("%s access from %s", request.path, addon.slug)
            request[REQUEST_FROM] = addon.slug

        if not request.get(REQUEST_FROM):
            raise HTTPUnauthorized()
        return await handler(request)
Beispiel #3
0
    async def _handle(
        self, request: web.Request, token: str, path: str
    ) -> Union[web.Response, web.StreamResponse, web.WebSocketResponse]:
        """Route data to Hass.io ingress service."""
        # validate token
        if token != self._valid_token:
            try:
                auth = self._hass.auth
                refresh_token = await auth.async_validate_access_token(token)
                if refresh_token is None:
                    raise HTTPUnauthorized() from None
                # remember the token as valid
                self._valid_token = token
            except Exception:
                raise HTTPUnauthorized() from None

        try:
            # Websockettoken
            if _is_websocket(request):
                return await self._handle_websocket(request, token, path)

            # Request
            return await self._handle_request(request, token, path)

        except aiohttp.ClientError as err:
            _LOGGER.debug("Ingress error with %s / %s: %s", token, path, err)

        raise HTTPBadGateway() from None
    async def validate_token(self, token: str) -> dict:
        """
        Request the JWT token validation to the associated UAA service

        Args:
            token: JWT token to validate

        Returns: user authenticated if the token is valid

        """
        async with ClientSession() as client:
            validate_token_url = self.URL_BASE.format(protocol=self._protocol, host=self._host, port=self._port,
                                                      path=self.PATHS['validate_token'])
            try:
                async with client.post(validate_token_url, data=dict(token=token)) as response:
                    if response.status == 200:
                        response_json = await response.json()
                    elif response.status == 500:
                        raise HTTPUnauthorized(reason='Wrong authorization token')
                    else:
                        raise HTTPInternalServerError(reason='Error calling uaa service')
            except Exception as ex:
                if not isinstance(ex, HTTPUnauthorized) and not isinstance(ex, HTTPInternalServerError):
                    raise ConnectionError(f'Error calling uaa service {str(ex)}')
                else:
                    raise ex

        if 'id' in response_json:
            return response_json
        else:
            raise HTTPUnauthorized(reason='Wrong authorization token')
Beispiel #5
0
 async def validate_user_credentials(self, username, token):
     session = self.session_map
     try:
         if session[username]['token'] == token:
             return session[username]
     except KeyError:
         raise HTTPUnauthorized()
     raise HTTPUnauthorized()
Beispiel #6
0
    async def check_auth(self, request):
        auth = request.headers.get('AUTHORIZATION')

        if not auth.startswith('Bearer '):
            raise HTTPUnauthorized()
        token = auth[7:]
        if token not in self.tokens:
            raise HTTPUnauthorized()

        if not self.tokens[token]:
            raise HTTPUnauthorized()
Beispiel #7
0
    def _check_access(self, request: web.Request):
        """Check if this call is from Supervisor."""
        # Check caller IP
        oppio_ip = os.environ["OPPIO"].split(":")[0]
        if request[KEY_REAL_IP] != ip_address(oppio_ip):
            _LOGGER.error("Invalid auth request from %s", request[KEY_REAL_IP])
            raise HTTPUnauthorized()

        # Check caller token
        if request[KEY_OPP_USER].id != self.user.id:
            _LOGGER.error("Invalid auth request from %s", request[KEY_OPP_USER].name)
            raise HTTPUnauthorized()
Beispiel #8
0
    async def wrapped(request, **kwargs):
        nonlocal provider
        oauth_endpoint_path = None
        oauth_email_regex = None
        provider_confs = request.app.config.get('OAUTH_PROVIDERS', {})
        if provider is None and 'default' in provider_confs:
            provider = 'default'

        if provider:
            try:
                provider_config = provider_confs[provider]
            except KeyError:
                if provider == "default" and provider_confs:
                    provider_config = next(iter(provider_confs.values()))
                else:
                    raise OAuthConfigurationException(
                        "No provider named {} configured".format(provider))
            oauth_endpoint_path = provider_config.get('ENDPOINT_PATH', None)
            oauth_email_regex = provider_config.get('EMAIL_REGEX', None)

        if not oauth_endpoint_path:
            oauth_endpoint_path = request.app.config.OAUTH_ENDPOINT_PATH

        if not oauth_email_regex:
            oauth_email_regex = request.app.config.OAUTH_EMAIL_REGEX

        # Do core oauth authentication once per session
        if SES_ACCESS_TOKEN_FIELD not in request[SES_SESSION_NAME]:
            if not redirect_login:
                raise HTTPUnauthorized(reason=f'User is not authenticated.')

            if provider:
                request[SES_SESSION_NAME][SES_OAUTH_PROVIDER_FIELD] = provider
            request[SES_SESSION_NAME][
                SES_AFTER_AUTH_REDIR_FIELD] = request.path
            return redirect(oauth_endpoint_path)

        # Shortcircuit out if we don't care about user info
        if not add_user_info:
            response = async_handler(request, **kwargs)
        else:
            # Otherwise retrieve the user info once per session
            user = await fetch_user_info(request, provider,
                                         oauth_endpoint_path, email_regex
                                         or oauth_email_regex)

            if user is None:
                raise HTTPUnauthorized(reason=f'Cannot fetch user info.')

            response = async_handler(request, user, **kwargs)

        return await response if isawaitable(response) else response
Beispiel #9
0
    async def handle(request):
        """Handle incoming request."""
        if not request.app[KEY_HASS].is_running:
            return web.Response(status=503)

        authenticated = request.get(KEY_AUTHENTICATED, False)

        if view.requires_auth:
            if authenticated:
                if "deprecate_warning_message" in request:
                    _LOGGER.warning(request["deprecate_warning_message"])
                await process_success_login(request)
            else:
                raise HTTPUnauthorized()

        _LOGGER.debug(
            "Serving %s to %s (auth: %s)",
            request.path,
            request.get(KEY_REAL_IP),
            authenticated,
        )

        try:
            result = handler(request, **request.match_info)

            if asyncio.iscoroutine(result):
                result = await result
        except vol.Invalid:
            raise HTTPBadRequest()
        except exceptions.ServiceNotFound:
            raise HTTPInternalServerError()
        except exceptions.Unauthorized:
            raise HTTPUnauthorized()

        if isinstance(result, web.StreamResponse):
            # The method handler returned a ready-made Response, how nice of it
            return result

        status_code = 200

        if isinstance(result, tuple):
            result, status_code = result

        if isinstance(result, str):
            result = result.encode("utf-8")
        elif result is None:
            result = b""
        elif not isinstance(result, bytes):
            assert False, ("Result should be None, string, bytes or Response. "
                           "Got: {}").format(result)

        return web.Response(body=result, status=status_code)
Beispiel #10
0
    async def handle(request: web.Request) -> web.StreamResponse:
        """Handle incoming request."""
        if request.app[KEY_HASS].is_stopping:
            return web.Response(status=HTTP_SERVICE_UNAVAILABLE)

        authenticated = request.get(KEY_AUTHENTICATED, False)

        if view.requires_auth and not authenticated:
            raise HTTPUnauthorized()

        _LOGGER.debug(
            "Serving %s to %s (auth: %s)",
            request.path,
            request.remote,
            authenticated,
        )

        try:
            result = handler(request, **request.match_info)

            if asyncio.iscoroutine(result):
                result = await result
        except vol.Invalid as err:
            raise HTTPBadRequest() from err
        except exceptions.ServiceNotFound as err:
            raise HTTPInternalServerError() from err
        except exceptions.Unauthorized as err:
            raise HTTPUnauthorized() from err

        if isinstance(result, web.StreamResponse):
            # The method handler returned a ready-made Response, how nice of it
            return result

        status_code = HTTP_OK

        if isinstance(result, tuple):
            result, status_code = result

        if isinstance(result, bytes):
            bresult = result
        elif isinstance(result, str):
            bresult = result.encode("utf-8")
        elif result is None:
            bresult = b""
        else:
            assert (
                False
            ), f"Result should be None, string, bytes or Response. Got: {result}"

        return web.Response(body=bresult, status=status_code)
Beispiel #11
0
    def _check_access(self, request: web.Request):
        """Check if this call is from Supervisor."""
        # Check caller IP
        hassio_ip = os.environ["HASSIO"].split(":")[0]
        if ip_address(request.transport.get_extra_info("peername")
                      [0]) != ip_address(hassio_ip):
            _LOGGER.error("Invalid auth request from %s", request.remote)
            raise HTTPUnauthorized()

        # Check caller token
        if request[KEY_HASS_USER].id != self.user.id:
            _LOGGER.error("Invalid auth request from %s",
                          request[KEY_HASS_USER].name)
            raise HTTPUnauthorized()
Beispiel #12
0
async def auth_check(request, handler):
    if 'ADMIN_USER' not in os.environ or 'ADMIN_PASSWORD' not in os.environ:
        raise Exception('Admin login credentials not set')

    if 'Authorization' not in request.headers:
        raise HTTPUnauthorized()

    auth = BasicAuth.decode(request.headers['Authorization'])
    if (auth.login != os.environ['ADMIN_USER'] or
            auth.password != os.environ['ADMIN_PASSWORD']):
        raise HTTPUnauthorized()

    response = await handler(request)
    return response
Beispiel #13
0
 async def __wrapper__(request: Request):
     user = await get_auth_user(request)
     if user is None:
         raise HTTPUnauthorized()
     if ensure_admin and not user.is_admin:
         raise HTTPForbidden()
     return await handler(request)
Beispiel #14
0
 async def wrap_api(api, *args, **kwargs):
     """Return API information."""
     coresys: CoreSys = api.coresys
     request: Request = args[0]
     if request[REQUEST_FROM] != coresys.homeassistant:
         raise HTTPUnauthorized()
     return await method(api, *args, **kwargs)
Beispiel #15
0
def apply_cors(request):
    """Second part of the cors function to validate."""
    from plone.server import app_settings
    headers = {}
    origin = request.headers.get('Origin', None)
    if origin:
        if not any([
                fnmatch.fnmatchcase(origin, o)
                for o in app_settings['cors']['allow_origin']
        ]):
            logger.error('Origin %s not allowed' % origin)
            raise HTTPUnauthorized()
        elif request.headers.get('Access-Control-Allow-Credentials', False):
            headers['Access-Control-Allow-Origin', origin]
        else:
            if any([o == "*" for o in app_settings['cors']['allow_origin']]):
                headers['Access-Control-Allow-Origin'] = '*'
            else:
                headers['Access-Control-Allow-Origin'] = origin
    if request.headers.get('Access-Control-Request-Method', None) != 'OPTIONS':
        if app_settings['cors']['allow_credentials']:
            headers['Access-Control-Allow-Credentials'] = 'True'
        if len(app_settings['cors']['allow_headers']):
            headers['Access-Control-Expose-Headers'] = \
                ', '.join(app_settings['cors']['allow_headers'])
    return headers
Beispiel #16
0
    async def _add_auth_info(self, request: web.Request):
        """Adds the authentication information, if any, to the request.

        Catches exceptions from decoding the payload and converts them to HTTP exceptions to be propagated.
        If authentication is disabled via :attr:`~_ignore_auth` doesn't do anything.

        Headers are kept in a `CIMultiDictProxy`_ so case of the header is not important.

        .. _CIMultiDictProxy: https://multidict.readthedocs.io/en/stable/multidict.html#multidict.CIMultiDictProxy
        """
        if self._ignore_auth:
            return None

        try:
            oidc_data = request.headers["X-Amzn-Oidc-Data"]
        except KeyError:
            logger.warning("No 'X-Amzn-Oidc-Data' header present. Dropping request.")
            raise HTTPProxyAuthenticationRequired()
        try:
            request["auth_payload"] = (self._header_name, await self._decode_payload(oidc_data))
        except ExpiredSignatureError:
            logger.warning("Got expired token. Dropping request.")
            raise HTTPUnauthorized()
        except DecodeError as e:
            logger.warning("Couldn't decode token. Dropping request.")
            logger.debug("Couldn't decode token: %s" % e)
            raise HTTPBadRequest()
Beispiel #17
0
async def jwt_auth(request, handler):
    def _get_token():
        raw_authorization = request.headers.get('Authorization', '')
        items = raw_authorization.split(' ')
        return items[1] if len(items) > 1 else None

    token = _get_token()
    if request.path != '/login':
        if token:
            try:
                request.jwt_data = jwt.decode(token, JWT_SECRET_KEY)
            except jwt.InvalidTokenError:
                raise HTTPUnauthorized(text='Token decode error')
        else:
            raise HTTPUnauthorized(text='Missing token')
    return await handler(request)
Beispiel #18
0
async def session_post(request: Request):
    session_maker = request.app['db_session_manager']
    session: Session = session_maker()
    try:
        data = await request.json()

        if data:
            user = session.query(Users).filter_by(login=data['login']).first()
            if not user:
                return HTTPNotFound()

            user_id = user.id
            if UsersSchema.check_password_hash(data['password'], user.password):
                response = HTTPAccepted()
                await remember(request, response, json.dumps({'user_id': user_id, 'login': user.login}))
                return response
            else:
                response = HTTPUnauthorized()
                if user_id:
                    await forget(request, response)
                return response
        else:
            return HTTPBadRequest()
    except Exception:
        raise
    finally:
        session.close()
Beispiel #19
0
def apply_cors(request: IRequest) -> dict:
    # deprecated, will be removed in next major release
    headers = {}
    origin = request.headers.get('Origin', None)
    if origin:
        if not any([
                fnmatch.fnmatchcase(origin, o)
                for o in app_settings['cors']['allow_origin']
        ]):
            logger.error('Origin %s not allowed' % origin)
            raise HTTPUnauthorized()
        elif request.headers.get('Access-Control-Allow-Credentials', False):
            headers['Access-Control-Allow-Origin', origin]
        else:
            if any([o == "*" for o in app_settings['cors']['allow_origin']]):
                headers['Access-Control-Allow-Origin'] = '*'
            else:
                headers['Access-Control-Allow-Origin'] = origin
    if request.headers.get('Access-Control-Request-Method', None) != 'OPTIONS':
        if app_settings['cors']['allow_credentials']:
            headers['Access-Control-Allow-Credentials'] = 'True'
        if len(app_settings['cors']['allow_headers']):
            headers['Access-Control-Expose-Headers'] = \
                ', '.join(app_settings['cors']['allow_headers'])
    return headers
Beispiel #20
0
    async def validate(self, token):
        """Return the user from the token."""
        if token.get('type') != 'bearer':
            return None

        if '.' not in token.get('token', ''):
            # quick way to check if actually might be jwt
            return None

        try:
            try:
                validated_jwt = jwt.decode(
                    token['token'],
                    app_settings['jwt']['secret'],
                    algorithms=[app_settings['jwt']['algorithm']])
            except jwt.exceptions.ExpiredSignatureError:
                logger.warn("Token Expired")
                raise HTTPUnauthorized()
            except jwt.InvalidIssuedAtError:
                logger.warn("Back to the future")
                validated_jwt = jwt.decode(
                    token['token'],
                    app_settings['jwt']['secret'],
                    algorithms=[app_settings['jwt']['algorithm']],
                    options=NON_IAT_VERIFY)

            user = GuillotinaUser(self.request)
            user.name = validated_jwt['fullname']
            user.id = validated_jwt['sub']
            return user

        except jwt.exceptions.DecodeError:
            pass

        return None
Beispiel #21
0
    def _process_auth(
        self, request: Request
    ) -> Tuple['Config', Union[SimpleNamespace, 'User'], Optional[str]]:
        config = self.config(request)
        if not config:
            raise HTTPNotFound()

        hass_user = request.get('hass_user')
        request_id = request.headers.get('X-Request-Id')
        remote_accepted = False
        if config.diagnostics_mode:
            remote_address = ipaddress.ip_address(request.remote)
            for network in config.diagnostics_mode:
                if remote_address in network:
                    remote_accepted = True
                    break

        if remote_accepted:
            # Facilitate the use of diagnostics mode by adding dummy data to the request
            if not hass_user:
                hass_user = SimpleNamespace(id=999999)
            if not request_id:
                request_id = str(uuid4()).upper()
        elif not hass_user:
            raise HTTPUnauthorized()
        elif not request_id:
            raise HTTPBadRequest()

        return config, hass_user, request_id
Beispiel #22
0
    async def handler(
        self, request: web.Request
    ) -> Union[web.Response, web.StreamResponse, web.WebSocketResponse]:
        """Route data to Supervisor ingress service."""

        # Check Ingress Session
        session = request.cookies.get(COOKIE_INGRESS)
        if not self.sys_ingress.validate_session(session):
            _LOGGER.warning("No valid ingress session %s", session)
            raise HTTPUnauthorized()

        # Process requests
        addon = self._extract_addon(request)
        path = request.match_info.get("path")
        try:
            # Websocket
            if _is_websocket(request):
                return await self._handle_websocket(request, addon, path)

            # Request
            return await self._handle_request(request, addon, path)

        except aiohttp.ClientError as err:
            _LOGGER.error("Ingress error: %s", err)

        raise HTTPBadGateway()
Beispiel #23
0
async def security_layer(request, handler):
    """Check security access of this layer."""
    coresys = request.app['coresys']
    hassio_token = request.headers.get(HEADER_TOKEN)

    # Ignore security check
    for rule in NO_SECURITY_CHECK:
        if rule.match(request.path):
            _LOGGER.debug("Passthrough %s", request.path)
            return await handler(request)

    # Need to be removed later
    if not hassio_token:
        _LOGGER.warning("No valid Hass.io token for API access!")
        request[REQUEST_FROM] = 'UNKNOWN'
        return await handler(request)

    # Home-Assistant
    if hassio_token == coresys.homeassistant.uuid:
        _LOGGER.debug("%s access from Home-Assistant", request.path)
        request[REQUEST_FROM] = 'homeassistant'
        return await handler(request)

    # Add-on
    addon = coresys.addons.from_uuid(hassio_token)
    if addon:
        _LOGGER.info("%s access from %s", request.path, addon.slug)
        request[REQUEST_FROM] = addon.slug
        return await handler(request)

    raise HTTPUnauthorized()
Beispiel #24
0
    async def auth(self, request: web.Request) -> bool:
        """Process login request."""
        addon = request[REQUEST_FROM]

        if not addon.access_auth_api:
            raise APIForbidden("Can't use Open Peer Power auth!")

        # BasicAuth
        if AUTHORIZATION in request.headers:
            return await self._process_basic(request, addon)

        # Json
        if request.headers.get(CONTENT_TYPE) == CONTENT_TYPE_JSON:
            data = await request.json()
            return await self._process_dict(request, addon, data)

        # URL encoded
        if request.headers.get(CONTENT_TYPE) == CONTENT_TYPE_URL:
            data = await request.post()
            return await self._process_dict(request, addon, data)

        raise HTTPUnauthorized(headers={
            WWW_AUTHENTICATE:
            'Basic realm="Open Peer Power Authentication"'
        })
Beispiel #25
0
    async def auth_wrapper(request):
        if 'X-API-KEY' not in request.headers:
            raise HTTPUnauthorized(text='No API Key provided')
        key = request.headers['X-API-KEY']
        if key != config["API_KEY"] or not config["API_KEY"]:
            raise HTTPForbidden(text='Wrong API Key')

        return await func(request)
Beispiel #26
0
    async def get(self, request):
        """Return the onboarding status."""
        if self._data["done"]:
            raise HTTPUnauthorized()

        hass = request.app["hass"]
        info = await async_get_system_info(hass)
        return self.json({"installation_type": info["installation_type"]})
Beispiel #27
0
    async def _check_login(self, username, password):
        """Check User credentials."""
        provider = self._get_provider()

        try:
            await provider.async_validate_login(username, password)
        except HomeAssistantError:
            raise HTTPUnauthorized() from None
Beispiel #28
0
    async def validate_session(self, request: web.Request) -> Dict[str, Any]:
        """Validate session and extending how long it's valid for."""
        data = await api_validate(VALIDATE_SESSION_DATA, request)

        # Check Ingress Session
        if not self.sys_ingress.validate_session(data[ATTR_SESSION]):
            _LOGGER.warning("No valid ingress session %s", data[ATTR_SESSION])
            raise HTTPUnauthorized()
Beispiel #29
0
async def login_user(username, password):
    db_mgr = await DatabaseManager.get_instance()
    result = await db_mgr.execute_query(
        "select username from users where username = %s "
        "and password = %s", username, password)
    if result[0] is None:
        raise HTTPUnauthorized(reason="Bad login or password")
    print("User logged in ", username)
Beispiel #30
0
    async def post(self):
        if not await self.has_permission():
            raise HTTPUnauthorized()

        drive: Drive = self.request.app['drive']
        se: SearchEngine = self.request.app['se']
        await se.clear_cache()
        changes = [_ async for _ in drive.sync()]
        return json_response(changes)