Merge pull request #2662 from coreos-inc/direct-login

Enable toggling of the direct login feature in the superuser panel
This commit is contained in:
josephschorr 2017-05-24 16:51:43 -04:00 committed by GitHub
commit 2ec43483a8
6 changed files with 142 additions and 53 deletions

View file

@ -53,59 +53,6 @@
</div>
</td>
</tr>
<tr>
<td class="non-input">Anonymous Access:</td>
<td colspan="2">
<div class="config-bool-field" binding="config.FEATURE_ANONYMOUS_ACCESS">
Enable Anonymous Access
</div>
<div class="help-text">
If enabled, public repositories and search can be accessed by anyone that can
reach the registry, even if they are not authenticated. Disable to only allow
authenticated users to view and pull "public" resources.
</div>
</td>
</tr>
<tr>
<td class="non-input">User Creation:</td>
<td colspan="2">
<div class="config-bool-field" binding="config.FEATURE_USER_CREATION">
Enable Open User Creation
</div>
<div class="help-text">
If enabled, user accounts can be created by anyone.
Users can always be created in the users panel under this superuser view.
</div>
</td>
</tr>
<tr>
<td class="non-input">Encrypted Client Password:</td>
<td colspan="2">
<div class="config-bool-field" binding="config.FEATURE_REQUIRE_ENCRYPTED_BASIC_AUTH">
Require Encrypted Client Passwords
</div>
<div class="help-text">
If enabled, users will not be able to login from the Docker command
line with a non-encrypted password and must generate an encrypted
password to use.
</div>
<div class="help-text" ng-if="config.AUTHENTICATION_TYPE != 'Database'">
This feature is <strong>highly recommended</strong> for setups with external authentication, as Docker currently stores passwords in <strong>plaintext</strong> on user's machines.
</div>
</td>
</tr>
<tr ng-show="config.FEATURE_MAILING">
<td class="non-input">Team Invitations:</td>
<td colspan="2">
<div class="config-bool-field" binding="config.FEATURE_REQUIRE_TEAM_INVITE">
Require Team Invitations
</div>
<div class="help-text">
If enabled, when adding a new user to a team, they will receive an invitation to join the team, with the option to decline.
Otherwise, users will be immediately part of a team when added by a team administrator.
</div>
</td>
</tr>
</table>
</div>
</div>
@ -1149,6 +1096,95 @@
</div>
</div> <!-- /External Authentication -->
<!-- Access settings -->
<div class="co-panel">
<div class="co-panel-heading">
<i class="fa fa-user-circle"></i> Access Settings
</div>
<div class="co-panel-body">
<div class="description">
<p>Various settings around access and authentication to the registry.</p>
</div>
<table class="config-table">
<tr>
<td class="non-input">Basic Credentials Login:</td>
<td colspan="2">
<div class="config-bool-field" binding="config.FEATURE_DIRECT_LOGIN" ng-if="getOIDCProviders(config).length || config.FEATURE_GITHUB_LOGIN || config.FEATURE_GOOGLE_LOGIN">
Login to User Interface via credentials
</div>
<div ng-if="!getOIDCProviders(config).length && !config.FEATURE_GITHUB_LOGIN && !config.FEATURE_GOOGLE_LOGIN">
<div ng-if="!config.FEATURE_DIRECT_LOGIN" class="co-alert co-alert-danger">
Login to User Interface via credentials must be enabled. <a ng-click="enableFeature(config, 'FEATURE_DIRECT_LOGIN')">Click here to enable</a>.
</div>
<div ng-if="config.FEATURE_DIRECT_LOGIN">
Login to User Interface via credentials is <strong>enabled</strong> (requires at least one OIDC provider to disable)
</div>
</div>
<div class="help-text">
If enabled, users will be able to login to the <strong>user interface</strong> via their username and password credentials.
</div>
<div class="help-text">
If <strong>disabled</strong>, users will only be able to login to the <strong>user interface</strong> via one of the configured External Authentication providers.
</div>
</td>
</tr>
<tr>
<td class="non-input">Anonymous Access:</td>
<td colspan="2">
<div class="config-bool-field" binding="config.FEATURE_ANONYMOUS_ACCESS">
Enable Anonymous Access
</div>
<div class="help-text">
If enabled, public repositories and search can be accessed by anyone that can
reach the registry, even if they are not authenticated. Disable to only allow
authenticated users to view and pull "public" resources.
</div>
</td>
</tr>
<tr>
<td class="non-input">User Creation:</td>
<td colspan="2">
<div class="config-bool-field" binding="config.FEATURE_USER_CREATION">
Enable Open User Creation
</div>
<div class="help-text">
If enabled, user accounts can be created by anyone.
Users can always be created in the users panel under this superuser view.
</div>
</td>
</tr>
<tr>
<td class="non-input">Encrypted Client Password:</td>
<td colspan="2">
<div class="config-bool-field" binding="config.FEATURE_REQUIRE_ENCRYPTED_BASIC_AUTH">
Require Encrypted Client Passwords
</div>
<div class="help-text">
If enabled, users will not be able to login from the Docker command
line with a non-encrypted password and must generate an encrypted
password to use.
</div>
<div class="help-text" ng-if="config.AUTHENTICATION_TYPE != 'Database'">
This feature is <strong>highly recommended</strong> for setups with external authentication, as Docker currently stores passwords in <strong>plaintext</strong> on user's machines.
</div>
</td>
</tr>
<tr ng-show="config.FEATURE_MAILING">
<td class="non-input">Team Invitations:</td>
<td colspan="2">
<div class="config-bool-field" binding="config.FEATURE_REQUIRE_TEAM_INVITE">
Require Team Invitations
</div>
<div class="help-text">
If enabled, when adding a new user to a team, they will receive an invitation to join the team, with the option to decline.
Otherwise, users will be immediately part of a team when added by a team administrator.
</div>
</td>
</tr>
</table>
</div>
</div> <!-- /Access settings -->
<!-- Build Support -->
<div class="co-panel">

View file

@ -23,6 +23,8 @@ angular.module("core-config-setup", ['angularFileUpload'])
{'id': 'time-machine', 'title': 'Time Machine'},
{'id': 'access', 'title': 'Access Settings'},
{'id': 'ssl', 'title': 'SSL certificate and key', 'condition': function(config) {
return config.PREFERRED_URL_SCHEME == 'https';
}},
@ -136,6 +138,10 @@ angular.module("core-config-setup", ['angularFileUpload'])
]
};
$scope.enableFeature = function(config, feature) {
config[feature] = true;
};
$scope.validateHostname = function(hostname) {
if (hostname.indexOf('127.0.0.1') == 0 || hostname.indexOf('localhost') == 0) {
return 'Please specify a non-localhost hostname. "localhost" will refer to the container, not your machine.'

View file

@ -19,6 +19,7 @@ def add_enterprise_config_defaults(config_obj, current_secret_key, hostname):
config_obj['FEATURE_REQUIRE_TEAM_INVITE'] = config_obj.get('FEATURE_REQUIRE_TEAM_INVITE', True)
config_obj['FEATURE_CHANGE_TAG_EXPIRATION'] = config_obj.get('FEATURE_CHANGE_TAG_EXPIRATION',
True)
config_obj['FEATURE_DIRECT_LOGIN'] = config_obj.get('FEATURE_DIRECT_LOGIN', True)
# Default features that are off.
config_obj['FEATURE_MAILING'] = config_obj.get('FEATURE_MAILING', False)

View file

@ -20,6 +20,7 @@ from util.config.validators.validate_gitlab_trigger import GitLabTriggerValidato
from util.config.validators.validate_github import GitHubLoginValidator, GitHubTriggerValidator
from util.config.validators.validate_oidc import OIDCLoginValidator
from util.config.validators.validate_timemachine import TimeMachineValidator
from util.config.validators.validate_access import AccessSettingsValidator
logger = logging.getLogger(__name__)
@ -55,6 +56,7 @@ VALIDATORS = {
BittorrentValidator.name: BittorrentValidator.validate,
OIDCLoginValidator.name: OIDCLoginValidator.validate,
TimeMachineValidator.name: TimeMachineValidator.validate,
AccessSettingsValidator.name: AccessSettingsValidator.validate,
}
def validate_service_for_config(service, config, password=None):

View file

@ -0,0 +1,22 @@
import pytest
from util.config.validators import ConfigValidationException
from util.config.validators.validate_access import AccessSettingsValidator
from test.fixtures import *
@pytest.mark.parametrize('unvalidated_config, expected_exception', [
({}, None),
({'FEATURE_DIRECT_LOGIN': False}, ConfigValidationException),
({'FEATURE_DIRECT_LOGIN': False, 'SOMETHING_LOGIN_CONFIG': {}}, None),
({'FEATURE_DIRECT_LOGIN': False, 'FEATURE_GITHUB_LOGIN': True}, None),
({'FEATURE_DIRECT_LOGIN': False, 'FEATURE_GOOGLE_LOGIN': True}, None),
])
def test_validate_invalid_oidc_login_config(unvalidated_config, expected_exception, app):
validator = AccessSettingsValidator()
if expected_exception is not None:
with pytest.raises(expected_exception):
validator.validate(unvalidated_config, None, None)
else:
validator.validate(unvalidated_config, None, None)

View file

@ -0,0 +1,22 @@
from app import app
from util.config.validators import BaseValidator, ConfigValidationException
from oauth.loginmanager import OAuthLoginManager
from oauth.oidc import OIDCLoginService
class AccessSettingsValidator(BaseValidator):
name = "access"
@classmethod
def validate(cls, config, user, user_password):
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)]
if not github_login and not google_login and not custom_oidc:
msg = 'Cannot disable credentials login to UI without configured OIDC service'
raise ConfigValidationException(msg)