Change validators to use the validator_context
Change InstanceKeys to take a namedtuple for context
This commit is contained in:
parent
e967fde3ae
commit
554d4f47a8
31 changed files with 172 additions and 69 deletions
|
@ -15,6 +15,6 @@ class BaseValidator(object):
|
|||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Raises Exception if failure to validate. """
|
||||
pass
|
||||
|
|
|
@ -6,13 +6,15 @@ class AccessSettingsValidator(BaseValidator):
|
|||
name = "access"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
config = validator_context.config
|
||||
client = validator_context.http_client
|
||||
|
||||
if not config.get('FEATURE_DIRECT_LOGIN', True):
|
||||
# Make sure we have at least one OIDC enabled.
|
||||
github_login = config.get('FEATURE_GITHUB_LOGIN', False)
|
||||
google_login = config.get('FEATURE_GOOGLE_LOGIN', False)
|
||||
|
||||
client = app.config['HTTPCLIENT']
|
||||
login_manager = OAuthLoginManager(config, client=client)
|
||||
custom_oidc = [s for s in login_manager.services if isinstance(s, OIDCLoginService)]
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@ class ActionLogArchivingValidator(BaseValidator):
|
|||
name = "actionlogarchiving"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
config = validator_context.config
|
||||
|
||||
""" Validates the action log archiving configuration. """
|
||||
if not config.get('FEATURE_ACTION_LOG_ROTATION', False):
|
||||
return
|
||||
|
|
|
@ -4,7 +4,9 @@ class AppTokenAuthValidator(BaseValidator):
|
|||
name = "apptoken-auth"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
config = validator_context.config
|
||||
|
||||
if config.get('AUTHENTICATION_TYPE', 'Database') != 'AppToken':
|
||||
return
|
||||
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
from bitbucket import BitBucket
|
||||
|
||||
from util import get_app_url
|
||||
from util import get_app_url_from_scheme_hostname
|
||||
from util.config.validators import BaseValidator, ConfigValidationException
|
||||
|
||||
class BitbucketTriggerValidator(BaseValidator):
|
||||
name = "bitbucket-trigger"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates the config for BitBucket. """
|
||||
config = validator_context.config
|
||||
|
||||
trigger_config = config.get('BITBUCKET_TRIGGER_CONFIG')
|
||||
if not trigger_config:
|
||||
raise ConfigValidationException('Missing client ID and client secret')
|
||||
|
@ -21,7 +23,7 @@ class BitbucketTriggerValidator(BaseValidator):
|
|||
|
||||
key = trigger_config['CONSUMER_KEY']
|
||||
secret = trigger_config['CONSUMER_SECRET']
|
||||
callback_url = '%s/oauth1/bitbucket/callback/trigger/' % (get_app_url(app.config))
|
||||
callback_url = '%s/oauth1/bitbucket/callback/trigger/' % (get_app_url(validator_context.scheme_and_hostname))
|
||||
|
||||
bitbucket_client = BitBucket(key, secret, callback_url)
|
||||
(result, _, _) = bitbucket_client.get_authorization_url()
|
||||
|
|
|
@ -7,8 +7,10 @@ class DatabaseValidator(BaseValidator):
|
|||
name = "database"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates connecting to the database. """
|
||||
config = validator_context.config
|
||||
|
||||
try:
|
||||
validate_database_url(config['DB_URI'], config.get('DB_CONNECTION_ARGS', {}))
|
||||
except OperationalError as ex:
|
||||
|
|
|
@ -7,9 +7,14 @@ class EmailValidator(BaseValidator):
|
|||
name = "mail"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates sending email. """
|
||||
with app.app_context():
|
||||
config = validator_context.config
|
||||
user = validator_context.user
|
||||
app_context = validator_context.context
|
||||
registry_title = validator_context.registry_title
|
||||
|
||||
with app_context():
|
||||
test_app = Flask("mail-test-app")
|
||||
test_app.config.update(config)
|
||||
test_app.config.update({
|
||||
|
@ -18,7 +23,7 @@ class EmailValidator(BaseValidator):
|
|||
})
|
||||
|
||||
test_mail = Mail(test_app)
|
||||
test_msg = Message("Test e-mail from %s" % app.config['REGISTRY_TITLE'],
|
||||
test_msg = Message("Test e-mail from %s" % registry_title,
|
||||
sender=config.get('MAIL_DEFAULT_SENDER'))
|
||||
test_msg.add_recipient(user.email)
|
||||
test_mail.send(test_msg)
|
||||
|
|
|
@ -6,8 +6,11 @@ class BaseGitHubValidator(BaseValidator):
|
|||
config_key = None
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates the OAuth credentials and API endpoint for a Github service. """
|
||||
config = validator_context.config
|
||||
client = validator_context.http_client
|
||||
|
||||
github_config = config.get(cls.config_key)
|
||||
if not github_config:
|
||||
raise ConfigValidationException('Missing GitHub client id and client secret')
|
||||
|
@ -29,9 +32,8 @@ class BaseGitHubValidator(BaseValidator):
|
|||
raise ConfigValidationException('Organization restriction must have at least one allowed ' +
|
||||
'organization')
|
||||
|
||||
client = app.config['HTTPCLIENT']
|
||||
oauth = GithubOAuthService(config, cls.config_key)
|
||||
result = oauth.validate_client_id_and_secret(client, app.config)
|
||||
result = oauth.validate_client_id_and_secret(client)
|
||||
if not result:
|
||||
raise ConfigValidationException('Invalid client id or client secret')
|
||||
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
from oauth.services.gitlab import GitLabOAuthService
|
||||
from util.config import URLSchemeAndHostname
|
||||
from util.config.validators import BaseValidator, ConfigValidationException
|
||||
|
||||
class GitLabTriggerValidator(BaseValidator):
|
||||
name = "gitlab-trigger"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates the OAuth credentials and API endpoint for a GitLab service. """
|
||||
config = validator_context.config
|
||||
url_scheme_and_hostname = validator_context.url_scheme_and_hostname
|
||||
client = validator_context.http_client
|
||||
|
||||
github_config = config.get('GITLAB_TRIGGER_CONFIG')
|
||||
if not github_config:
|
||||
raise ConfigValidationException('Missing GitLab client id and client secret')
|
||||
|
@ -23,9 +26,7 @@ class GitLabTriggerValidator(BaseValidator):
|
|||
if not github_config.get('CLIENT_SECRET'):
|
||||
raise ConfigValidationException('Missing Client Secret')
|
||||
|
||||
client = app.config['HTTPCLIENT']
|
||||
oauth = GitLabOAuthService(config, 'GITLAB_TRIGGER_CONFIG')
|
||||
url_scheme_and_hostname = URLSchemeAndHostname(app.config['PREFERRED_URL_SCHEME'], app.config['SERVER_HOSTNAME'])
|
||||
result = oauth.validate_client_id_and_secret(client, url_scheme_and_hostname)
|
||||
if not result:
|
||||
raise ConfigValidationException('Invalid client id or client secret')
|
||||
|
|
|
@ -5,8 +5,11 @@ class GoogleLoginValidator(BaseValidator):
|
|||
name = "google-login"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates the Google Login client ID and secret. """
|
||||
config = validator_context.config
|
||||
client = validator_context.http_client
|
||||
|
||||
google_login_config = config.get('GOOGLE_LOGIN_CONFIG')
|
||||
if not google_login_config:
|
||||
raise ConfigValidationException('Missing client ID and client secret')
|
||||
|
@ -17,8 +20,8 @@ class GoogleLoginValidator(BaseValidator):
|
|||
if not google_login_config.get('CLIENT_SECRET'):
|
||||
raise ConfigValidationException('Missing Client Secret')
|
||||
|
||||
client = app.config['HTTPCLIENT']
|
||||
oauth = GoogleOAuthService(config, 'GOOGLE_LOGIN_CONFIG')
|
||||
result = oauth.validate_client_id_and_secret(client, app.config)
|
||||
# TODO(sam): the google oauth doesn't need the app config, but when refactoring pass in the URLSchemeandHostname
|
||||
result = oauth.validate_client_id_and_secret(client)
|
||||
if not result:
|
||||
raise ConfigValidationException('Invalid client id or client secret')
|
||||
|
|
|
@ -6,8 +6,14 @@ class JWTAuthValidator(BaseValidator):
|
|||
name = "jwt"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app, public_key_path=None):
|
||||
def validate(cls, validator_context, public_key_path=None):
|
||||
""" Validates the JWT authentication system. """
|
||||
config = validator_context.config
|
||||
user = validator_context.user
|
||||
user_password = validator_context.user_password
|
||||
http_client = validator_context.http_client
|
||||
jwt_auth_max = validator_context.jwt_auth_max
|
||||
|
||||
if config.get('AUTHENTICATION_TYPE', 'Database') != 'JWT':
|
||||
return
|
||||
|
||||
|
@ -27,8 +33,8 @@ class JWTAuthValidator(BaseValidator):
|
|||
# the key cannot be found.
|
||||
users = ExternalJWTAuthN(verify_endpoint, query_endpoint, getuser_endpoint, issuer,
|
||||
OVERRIDE_CONFIG_DIRECTORY,
|
||||
app.config['HTTPCLIENT'],
|
||||
app.config.get('JWT_AUTH_MAX_FRESH_S', 300),
|
||||
http_client,
|
||||
jwt_auth_max,
|
||||
public_key_path=public_key_path,
|
||||
requires_email=config.get('FEATURE_MAILING', True))
|
||||
|
||||
|
|
|
@ -5,8 +5,12 @@ class KeystoneValidator(BaseValidator):
|
|||
name = "keystone"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates the Keystone authentication system. """
|
||||
config = validator_context.config
|
||||
user = validator_context.user
|
||||
user_password = validator_context.user_password
|
||||
|
||||
if config.get('AUTHENTICATION_TYPE', 'Database') != 'Keystone':
|
||||
return
|
||||
|
||||
|
|
|
@ -11,8 +11,11 @@ class LDAPValidator(BaseValidator):
|
|||
name = "ldap"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates the LDAP connection. """
|
||||
config = validator_context.config
|
||||
user = validator_context.user
|
||||
user_password = validator_context.user_password
|
||||
if config.get('AUTHENTICATION_TYPE', 'Database') != 'LDAP':
|
||||
return
|
||||
|
||||
|
|
|
@ -6,8 +6,10 @@ class OIDCLoginValidator(BaseValidator):
|
|||
name = "oidc-login"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
client = app.config['HTTPCLIENT']
|
||||
def validate(cls, validator_context):
|
||||
config = validator_context.config
|
||||
client = validator_context.http_client
|
||||
|
||||
login_manager = OAuthLoginManager(config, client=client)
|
||||
for service in login_manager.services:
|
||||
if not isinstance(service, OIDCLoginService):
|
||||
|
|
|
@ -6,8 +6,10 @@ class RedisValidator(BaseValidator):
|
|||
name = "redis"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates connecting to redis. """
|
||||
config = validator_context.config
|
||||
|
||||
redis_config = config.get('BUILDLOGS_REDIS', {})
|
||||
if not 'host' in redis_config:
|
||||
raise ConfigValidationException('Missing redis hostname')
|
||||
|
|
|
@ -8,13 +8,16 @@ class SecurityScannerValidator(BaseValidator):
|
|||
name = "security-scanner"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates the configuration for talking to a Quay Security Scanner. """
|
||||
config = validator_context.config
|
||||
client = validator_context.http_client
|
||||
app = None #TODO(sam) validate with joey's pr about security scanner api
|
||||
|
||||
if not config.get('FEATURE_SECURITY_SCANNER', False):
|
||||
return
|
||||
|
||||
client = app.config['HTTPCLIENT']
|
||||
api = SecurityScannerAPI(app, config, None, client=client, skip_validation=True)
|
||||
api = SecurityScannerAPI(app.config, config, None, client=client, skip_validation=True)
|
||||
|
||||
if not config.get('TESTING', False):
|
||||
# Generate a temporary Quay key to use for signing the outgoing requests.
|
||||
|
|
|
@ -8,8 +8,10 @@ class SignerValidator(BaseValidator):
|
|||
name = "signer"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates the GPG public+private key pair used for signing converted ACIs. """
|
||||
config = validator_context.config
|
||||
|
||||
if config.get('SIGNING_ENGINE') is None:
|
||||
return
|
||||
|
||||
|
|
|
@ -8,8 +8,9 @@ class SSLValidator(BaseValidator):
|
|||
name = "ssl"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates the SSL configuration (if enabled). """
|
||||
config = validator_context.config
|
||||
|
||||
# Skip if non-SSL.
|
||||
if config.get('PREFERRED_URL_SCHEME', 'http') != 'https':
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
from _init import config_provider
|
||||
from storage import get_storage_driver
|
||||
from util.config.validators import BaseValidator, ConfigValidationException
|
||||
from util.ipresolver import NoopIPResolver
|
||||
|
||||
ip_resolver = NoopIPResolver()
|
||||
|
||||
|
||||
class StorageValidator(BaseValidator):
|
||||
name = "registry-storage"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates registry storage. """
|
||||
config = validator_context.config
|
||||
client = validator_context.http_client
|
||||
ip_resolver = validator_context.ip_resolver
|
||||
|
||||
replication_enabled = config.get('FEATURE_STORAGE_REPLICATION', False)
|
||||
|
||||
providers = _get_storage_providers(config).items()
|
||||
providers = _get_storage_providers(config, ip_resolver).items()
|
||||
if not providers:
|
||||
raise ConfigValidationException('Storage configuration required')
|
||||
|
||||
|
@ -25,7 +26,7 @@ class StorageValidator(BaseValidator):
|
|||
'with storage replication')
|
||||
|
||||
# Run validation on the driver.
|
||||
driver.validate(app.config['HTTPCLIENT'])
|
||||
driver.validate(client)
|
||||
|
||||
# Run setup on the driver if the read/write succeeded.
|
||||
driver.setup()
|
||||
|
@ -34,7 +35,7 @@ class StorageValidator(BaseValidator):
|
|||
raise ConfigValidationException('Invalid storage configuration: %s: %s' % (name, msg))
|
||||
|
||||
|
||||
def _get_storage_providers(config):
|
||||
def _get_storage_providers(config, ip_resolver):
|
||||
storage_config = config.get('DISTRIBUTED_STORAGE_CONFIG', {})
|
||||
drivers = {}
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ class TimeMachineValidator(BaseValidator):
|
|||
name = "time-machine"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
config = validator_context.config
|
||||
|
||||
if not 'DEFAULT_TAG_EXPIRATION' in config:
|
||||
# Old style config
|
||||
return
|
||||
|
|
|
@ -11,15 +11,16 @@ class BittorrentValidator(BaseValidator):
|
|||
name = "bittorrent"
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, user, user_password, app):
|
||||
def validate(cls, validator_context):
|
||||
""" Validates the configuration for using BitTorrent for downloads. """
|
||||
config = validator_context.config
|
||||
client = validator_context.http_client
|
||||
|
||||
announce_url = config.get('BITTORRENT_ANNOUNCE_URL')
|
||||
if not announce_url:
|
||||
raise ConfigValidationException('Missing announce URL')
|
||||
|
||||
# Ensure that the tracker is reachable and accepts requests signed with a registry key.
|
||||
client = app.config['HTTPCLIENT']
|
||||
|
||||
params = {
|
||||
'info_hash': sha1('test').digest(),
|
||||
'peer_id': '-QUAY00-6wfG2wk6wWLc',
|
||||
|
|
Reference in a new issue