def is_trusted_requester(): """Returns True if the requester can see the service metadata. Used in metadata endpoint. Returns: True if the current identity is an admin or the config service. """ if auth.is_superuser() or auth.is_admin(): return True settings = common.ConfigSettings.cached() if settings and settings.trusted_config_account: identity = auth.get_current_identity() if identity == settings.trusted_config_account: return True return False
class ConfigApi(remote.Service): """Configuration service.""" @auth.endpoints_method(ConfigSettingsMessage, ConfigSettingsMessage, http_method='POST') @auth.require(lambda: auth.is_superuser() or auth.is_admin()) def settings(self, request): """Reads/writes config service location. Accessible only by admins.""" settings = common.ConfigSettings.fetch() or common.ConfigSettings() delta = {} if request.service_hostname is not None: delta['service_hostname'] = request.service_hostname if request.trusted_config_account is not None: try: delta['trusted_config_account'] = auth.Identity.from_bytes( request.trusted_config_account) except ValueError as ex: raise endpoints.BadRequestException( 'Invalid trusted_config_account %s: %s' % (request.trusted_config_account, ex.message)) changed = settings.modify( updated_by=auth.get_current_identity().to_bytes(), **delta) if changed: logging.warning('Updated config settings') settings = common.ConfigSettings.fetch() or settings return ConfigSettingsMessage( service_hostname=settings.service_hostname, trusted_config_account=(settings.trusted_config_account.to_bytes() if settings.trusted_config_account else None)) @auth.endpoints_method(ValidateRequestMessage, ValidateResponseMessage, http_method='POST') @auth.require(is_trusted_requester) def validate(self, request): """Validates a config. Compatible with validation protocol described in ValidationCfg message of /appengine/config_service/proto/service_config.proto. """ ctx = validation.Context() validation.validate(request.config_set, request.path, request.content, ctx) res = ValidateResponseMessage() for m in ctx.result().messages: res.messages.append( ValidationMessage( severity=common.Severity.lookup_by_number(m.severity), text=m.text, )) return res @auth.endpoints_method(message_types.VoidMessage, ServiceDynamicMetadata, http_method='GET', path='metadata') @auth.require(is_trusted_requester) def get_metadata(self, _request): """Describes a service. Used by config service to discover other services. """ meta = ServiceDynamicMetadata(version=METADATA_FORMAT_VERSION) http_headers = dict(self.request_state.headers) assert 'host' in http_headers, http_headers meta.validation = meta.Validator( url='https://{hostname}/_ah/api/{name}/{version}/{path}validate'. format( hostname=http_headers['host'], name=self.api_info.name, version=self.api_info.version, path=self.api_info.path or '', )) for p in sorted(get_default_rule_set().patterns()): meta.validation.patterns.append(ConfigPattern(**p._asdict())) return meta
def is_admin(): if auth.is_superuser(): return True acl_cfg = get_acl_cfg() return auth.is_group_member(acl_cfg and acl_cfg.admin_group or auth.ADMIN_GROUP)