mirror of https://github.com/portainer/portainer
feat(oauth): update OAuth UX
parent
16226b1202
commit
de76ba4e67
|
@ -55,7 +55,7 @@ func (handler *Handler) validateOAuth(w http.ResponseWriter, r *http.Request) *h
|
|||
}
|
||||
|
||||
if user == nil && !settings.OAuthSettings.OAuthAutoCreateUsers {
|
||||
return &httperror.HandlerError{http.StatusForbidden, "Unregistered account", portainer.ErrUnauthorized}
|
||||
return &httperror.HandlerError{http.StatusForbidden, "Account not created beforehand in Portainer and automatic user provisioning not enabled", portainer.ErrUnauthorized}
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
|
|
|
@ -23,9 +23,18 @@ type Service struct{}
|
|||
|
||||
// GetAccessToken takes an access code and exchanges it for an access token from portainer OAuthSettings token endpoint
|
||||
func (*Service) GetAccessToken(code string, settings *portainer.OAuthSettings) (string, error) {
|
||||
unescapedCode, err := url.QueryUnescape(code)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
config := buildConfig(settings)
|
||||
token, err := config.Exchange(context.Background(), code)
|
||||
return token.AccessToken, err
|
||||
token, err := config.Exchange(context.Background(), unescapedCode)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return token.AccessToken, nil
|
||||
}
|
||||
|
||||
// GetUsername takes a token and retrieves the portainer OAuthSettings user identifier from resource server.
|
||||
|
@ -109,7 +118,6 @@ func buildConfig(oauthSettings *portainer.OAuthSettings) *oauth2.Config {
|
|||
ClientSecret: oauthSettings.ClientSecret,
|
||||
Endpoint: endpoint,
|
||||
RedirectURL: oauthSettings.RedirectURI,
|
||||
// TODO figure out how to handle different providers, see https://github.com/golang/oauth2/issues/119
|
||||
Scopes: []string{oauthSettings.Scopes},
|
||||
Scopes: []string{oauthSettings.Scopes},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
angular.module('portainer.extensions.oauth')
|
||||
.controller('OAuthProviderSelectorController', function OAuthProviderSelectorController() {
|
||||
var ctrl = this;
|
||||
|
||||
this.providers = [
|
||||
{
|
||||
userIdentifier: 'mail',
|
||||
scope: 'id,email,name',
|
||||
name: 'microsoft'
|
||||
},
|
||||
{
|
||||
authUrl: 'https://accounts.google.com/o/oauth2/auth',
|
||||
accessTokenUrl: 'https://accounts.google.com/o/oauth2/token',
|
||||
resourceUrl: 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json',
|
||||
userIdentifier: 'email',
|
||||
scopes: 'profile email',
|
||||
name: 'google'
|
||||
},
|
||||
{
|
||||
authUrl: 'https://github.com/login/oauth/authorize',
|
||||
accessTokenUrl: 'https://github.com/login/oauth/access_token',
|
||||
resourceUrl: 'https://api.github.com/user',
|
||||
userIdentifier: 'login',
|
||||
scopes: 'id email name',
|
||||
name: 'github'
|
||||
},
|
||||
{
|
||||
name: 'custom'
|
||||
}
|
||||
];
|
||||
|
||||
this.$onInit = onInit;
|
||||
|
||||
function onInit() {
|
||||
console.log(ctrl.provider.authUrl);
|
||||
if (ctrl.provider.authUrl) {
|
||||
ctrl.provider = getProviderByURL(ctrl.provider.authUrl);
|
||||
} else {
|
||||
ctrl.provider = ctrl.providers[0];
|
||||
}
|
||||
ctrl.onSelect(ctrl.provider);
|
||||
}
|
||||
|
||||
function getProviderByURL(providerAuthURL) {
|
||||
if (providerAuthURL.indexOf('login.microsoftonline.com') !== -1) {
|
||||
return ctrl.providers[0];
|
||||
}
|
||||
else if (providerAuthURL.indexOf('accounts.google.com') !== -1) {
|
||||
return ctrl.providers[1];
|
||||
}
|
||||
else if (providerAuthURL.indexOf('github.com') !== -1) {
|
||||
return ctrl.providers[2];
|
||||
}
|
||||
return ctrl.provider[3];
|
||||
}
|
||||
});
|
|
@ -1,17 +1,49 @@
|
|||
<div class="col-sm-12 form-section-title">
|
||||
Provider
|
||||
</div>
|
||||
Provider
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<select
|
||||
class="form-control"
|
||||
id="oauth-provider-selector"
|
||||
ng-model="$ctrl.selectedProvider"
|
||||
ng-change="$ctrl.onSelect($ctrl.selectedProvider)"
|
||||
ng-options="provider as provider.name for provider in $ctrl.providers"
|
||||
>
|
||||
</select>
|
||||
<div class="form-group"></div>
|
||||
<div class="form-group" style="margin-bottom: 0">
|
||||
<div class="boxselector_wrapper">
|
||||
<div ng-click="$ctrl.onSelect($ctrl.provider)">
|
||||
<input type="radio" id="oauth_provider_microsoft" ng-model="$ctrl.provider" ng-value="$ctrl.providers[0]">
|
||||
<label for="oauth_provider_microsoft">
|
||||
<div class="boxselector_header">
|
||||
<i class="fab fa-microsoft" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
Microsoft
|
||||
</div>
|
||||
<p>Microsoft OAuth provider</p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-click="$ctrl.onSelect($ctrl.provider)">
|
||||
<input type="radio" id="oauth_provider_google" ng-model="$ctrl.provider" ng-value="$ctrl.providers[1]">
|
||||
<label for="oauth_provider_google">
|
||||
<div class="boxselector_header">
|
||||
<i class="fab fa-google" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
Google
|
||||
</div>
|
||||
<p>Google OAuth provider</p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-click="$ctrl.onSelect($ctrl.provider)">
|
||||
<input type="radio" id="oauth_provider_github" ng-model="$ctrl.provider" ng-value="$ctrl.providers[2]">
|
||||
<label for="oauth_provider_github">
|
||||
<div class="boxselector_header">
|
||||
<i class="fab fa-github" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
Github
|
||||
</div>
|
||||
<p>Github OAuth provider</p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-click="$ctrl.onSelect($ctrl.provider)">
|
||||
<input type="radio" id="oauth_provider_custom" ng-model="$ctrl.provider" ng-value="$ctrl.providers[3]">
|
||||
<label for="oauth_provider_custom">
|
||||
<div class="boxselector_header">
|
||||
<i class="fa fa-user-check" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
Custom
|
||||
</div>
|
||||
<p>Custom OAuth provider</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,20 +1,8 @@
|
|||
angular.module('portainer.extensions.oauth').component('oauthProvidersSelector', {
|
||||
templateUrl: 'app/extensions/oauth/components/oauth-providers-selector/oauth-providers-selector.html',
|
||||
bindings: {
|
||||
onSelect: '<'
|
||||
onSelect: '<',
|
||||
provider: '='
|
||||
},
|
||||
controller: function oauthProvidersSelectorController() {
|
||||
this.providers = [
|
||||
{
|
||||
name: 'Facebook',
|
||||
authUrl: 'https://www.facebook.com/v3.2/dialog/oauth',
|
||||
accessTokenUrl: 'https://graph.facebook.com/v3.2/oauth/access_token',
|
||||
resourceUrl: 'https://graph.facebook.com/v3.2/me?fields=email',
|
||||
userIdentifier: 'email'
|
||||
},
|
||||
{
|
||||
name: 'Custom'
|
||||
}
|
||||
];
|
||||
}
|
||||
controller: 'OAuthProviderSelectorController'
|
||||
});
|
||||
|
|
|
@ -1,11 +1,38 @@
|
|||
angular.module('portainer.extensions.oauth')
|
||||
.controller('OAuthSettingsController', function OAuthSettingsController() {
|
||||
this.onSelectProvider = onSelectProvider;
|
||||
.controller('OAuthSettingsController', function OAuthSettingsController() {
|
||||
var ctrl = this;
|
||||
|
||||
function onSelectProvider(provider) {
|
||||
this.settings.AuthorizationURI = provider.authUrl;
|
||||
this.settings.AccessTokenURI = provider.accessTokenUrl;
|
||||
this.settings.ResourceURI = provider.resourceUrl;
|
||||
this.settings.UserIdentifier = provider.userIdentifier;
|
||||
}
|
||||
});
|
||||
this.state = {
|
||||
provider: {},
|
||||
overrideConfiguration: false,
|
||||
microsoftTenantID: ''
|
||||
};
|
||||
|
||||
this.$onInit = onInit;
|
||||
this.onSelectProvider = onSelectProvider;
|
||||
this.onMicrosoftTenantIDChange = onMicrosoftTenantIDChange;
|
||||
|
||||
function onMicrosoftTenantIDChange() {
|
||||
var tenantID = ctrl.state.microsoftTenantID;
|
||||
|
||||
ctrl.settings.AuthorizationURI = _.replace('https://login.microsoftonline.com/TENANT_ID/oauth2/authorize', 'TENANT_ID', tenantID);
|
||||
ctrl.settings.AccessTokenURI = _.replace('https://login.microsoftonline.com/TENANT_ID/oauth2/token', 'TENANT_ID', tenantID);
|
||||
ctrl.settings.ResourceURI = _.replace('https://graph.windows.net/TENANT_ID/me?api-version=2013-11-08', 'TENANT_ID', tenantID);
|
||||
}
|
||||
|
||||
function onSelectProvider(provider) {
|
||||
ctrl.state.provider = provider;
|
||||
ctrl.settings.AuthorizationURI = provider.authUrl;
|
||||
ctrl.settings.AccessTokenURI = provider.accessTokenUrl;
|
||||
ctrl.settings.ResourceURI = provider.resourceUrl;
|
||||
ctrl.settings.UserIdentifier = provider.userIdentifier;
|
||||
ctrl.settings.Scopes = provider.scopes;
|
||||
}
|
||||
|
||||
function onInit() {
|
||||
if (ctrl.settings.RedirectURI === '') {
|
||||
ctrl.settings.RedirectURI = window.location.origin;
|
||||
}
|
||||
ctrl.state.provider.authUrl = ctrl.settings.AuthorizationURI;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,48 +1,61 @@
|
|||
<div>
|
||||
<!-- <oauth-providers-selector on-select="$ctrl.onSelectProvider" selected-provider="$ctrl.settings.provider" providers="$ctrl.providers"></oauth-providers-selector> -->
|
||||
<div class="col-sm-12 form-section-title">
|
||||
Automatic user provisioning
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<span class="col-sm-12 text-muted small">
|
||||
With automatic user provisioning enabled, Portainer will create user(s) automatically with standard user role. If
|
||||
disabled, users must be created in Portainer in order to login.
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<label for="oauth_provisioning"> Automatic user provisioning </label>
|
||||
<div class="col-sm-12 form-section-title">
|
||||
Automatic user provisioning
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<span class="col-sm-12 text-muted small">
|
||||
With automatic user provisioning enabled, Portainer will create user(s) automatically with standard user role. If
|
||||
disabled, users must be created in Portainer in order to login.
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 col-lg-2 control-label text-left">Automatic user provisioning</label>
|
||||
<label class="switch" style="margin-left: 20px">
|
||||
<input type="checkbox" ng-model="$ctrl.settings.OAuthAutoCreateUsers" /><i></i>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="$ctrl.settings.OAuthAutoCreateUsers">
|
||||
<div class="form-group">
|
||||
<span class="col-sm-12 text-muted small">
|
||||
The users created by the automatic provisioning feature can be added to a default team on creation. This setting is optional.
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="team_provisioning" class="col-sm-2">Default team</label>
|
||||
<span class="small text-muted" style="margin-left: 20px;" ng-if="$ctrl.teams.length === 0">
|
||||
You have not yet created any team. Head over the <a ui-sref="portainer.teams">teams view</a> to manage user teams.
|
||||
</span>
|
||||
<button type="button" class="btn btn-sm btn-danger" ng-click="$ctrl.settings.DefaultTeamID = null" ng-disabled="!$ctrl.settings.DefaultTeamID"
|
||||
ng-if="$ctrl.teams.length > 0">
|
||||
<i class="fa fa-times" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="col-sm-9 col-lg-9" ng-if="$ctrl.teams.length > 0">
|
||||
<select class="form-control" ng-model="$ctrl.settings.DefaultTeamID" ng-options="team.Id as team.Name for team in $ctrl.teams">
|
||||
</select>
|
||||
<div ng-if="$ctrl.settings.OAuthAutoCreateUsers">
|
||||
<div class="form-group">
|
||||
<span class="col-sm-12 text-muted small">
|
||||
The users created by the automatic provisioning feature can be added to a default team on creation. This setting is optional.
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 col-lg-2 control-label text-left">Default team</label>
|
||||
<span class="small text-muted" style="margin-left: 20px;" ng-if="$ctrl.teams.length === 0">
|
||||
You have not yet created any team. Head over the <a ui-sref="portainer.teams">teams view</a> to manage user teams.
|
||||
</span>
|
||||
<button type="button" class="btn btn-sm btn-danger" ng-click="$ctrl.settings.DefaultTeamID = null" ng-disabled="!$ctrl.settings.DefaultTeamID" ng-if="$ctrl.teams.length > 0"><i class="fa fa-times" aria-hidden="true"></i></button>
|
||||
<div class="col-sm-9 col-lg-9" ng-if="$ctrl.teams.length > 0">
|
||||
<select class="form-control" ng-model="$ctrl.settings.DefaultTeamID" ng-options="team.Id as team.Name for team in $ctrl.teams">
|
||||
<option value="">No team</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<oauth-providers-selector on-select="$ctrl.onSelectProvider" provider="$ctrl.state.provider"></oauth-providers-selector>
|
||||
|
||||
<div class="col-sm-12 form-section-title">OAuth Configuration</div>
|
||||
|
||||
<div class="form-group" ng-if="$ctrl.state.provider.name == 'microsoft'">
|
||||
<label for="oauth_microsoft_tenant_id" class="col-sm-3 col-lg-2 control-label text-left">
|
||||
Tenant ID
|
||||
<portainer-tooltip position="bottom" message="ID of the Azure AD directory in which you created the OAuth application"></portainer-tooltip>
|
||||
</label>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_microsoft_tenant_id"
|
||||
placeholder="xxxxxxxxxxxxxxxxxxxx"
|
||||
ng-model="$ctrl.state.microsoftTenantID"
|
||||
ng-change="$ctrl.onMicrosoftTenantIDChange()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="oauth_client_id" class="col-sm-3 col-lg-2 control-label text-left">
|
||||
Client ID
|
||||
|
@ -50,11 +63,11 @@
|
|||
</label>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_client_id"
|
||||
ng-model="$ctrl.settings.ClientID"
|
||||
placeholder="xxxxxxxxxxxxxxxxxxxx"
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_client_id"
|
||||
ng-model="$ctrl.settings.ClientID"
|
||||
placeholder="xxxxxxxxxxxxxxxxxxxx"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -63,129 +76,140 @@
|
|||
<label for="oauth_client_secret" class="col-sm-3 col-lg-2 control-label text-left">
|
||||
Client Secret
|
||||
<portainer-tooltip
|
||||
position="bottom"
|
||||
message="Client secret that authorization server supports"
|
||||
position="bottom"
|
||||
message="Client secret that authorization server supports"
|
||||
></portainer-tooltip>
|
||||
</label>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="oauth_client_secret"
|
||||
ng-model="$ctrl.settings.ClientSecret"
|
||||
placeholder="xxxxxxxxxxxxxxxxxxxx"
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="oauth_client_secret"
|
||||
ng-model="$ctrl.settings.ClientSecret"
|
||||
placeholder="xxxxxxxxxxxxxxxxxxxx"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group" ng-if="$ctrl.state.provider.name == 'custom' || $ctrl.state.overrideConfiguration">
|
||||
<label for="oauth_authorization_uri" class="col-sm-3 col-lg-2 control-label text-left">
|
||||
Authorization URI
|
||||
<portainer-tooltip
|
||||
position="bottom"
|
||||
message="URI where the user is redirected in order to login with OAuth provider"
|
||||
position="bottom"
|
||||
message="URI where the user is redirected in order to login with OAuth provider"
|
||||
></portainer-tooltip>
|
||||
</label>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_authorization_uri"
|
||||
ng-model="$ctrl.settings.AuthorizationURI"
|
||||
placeholder="https://example.com/oauth/authorize"
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_authorization_uri"
|
||||
ng-model="$ctrl.settings.AuthorizationURI"
|
||||
placeholder="https://example.com/oauth/authorize"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group" ng-if="$ctrl.state.provider.name == 'custom' || $ctrl.state.overrideConfiguration">
|
||||
<label for="oauth_access_token_uri" class="col-sm-3 col-lg-2 control-label text-left">
|
||||
Access Token URI
|
||||
<portainer-tooltip
|
||||
position="bottom"
|
||||
message="URI where portainer will attempt to obtain an access token"
|
||||
position="bottom"
|
||||
message="URI where portainer will attempt to obtain an access token"
|
||||
></portainer-tooltip>
|
||||
</label>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_access_token_uri"
|
||||
ng-model="$ctrl.settings.AccessTokenURI"
|
||||
placeholder="https://example.com/oauth/token"
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_access_token_uri"
|
||||
ng-model="$ctrl.settings.AccessTokenURI"
|
||||
placeholder="https://example.com/oauth/token"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group" ng-if="$ctrl.state.provider.name == 'custom' || $ctrl.state.overrideConfiguration">
|
||||
<label for="oauth_resource_uri" class="col-sm-3 col-lg-2 control-label text-left">
|
||||
Resource URI
|
||||
<portainer-tooltip
|
||||
position="bottom"
|
||||
message="URI where portainer will attempt to retrieve the user identifier value"
|
||||
position="bottom"
|
||||
message="URI where portainer will attempt to retrieve the user identifier value"
|
||||
></portainer-tooltip>
|
||||
</label>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_resource_uri"
|
||||
ng-model="$ctrl.settings.ResourceURI"
|
||||
placeholder="https://example.com/user"
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_resource_uri"
|
||||
ng-model="$ctrl.settings.ResourceURI"
|
||||
placeholder="https://example.com/user"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group" ng-if="$ctrl.state.provider.name == 'custom' || $ctrl.state.overrideConfiguration">
|
||||
<label for="oauth_redirect_uri" class="col-sm-3 col-lg-2 control-label text-left">
|
||||
Redirect URI
|
||||
<portainer-tooltip position="bottom" message="Set this as your portainer index"></portainer-tooltip>
|
||||
</label>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_redirect_uri"
|
||||
ng-model="$ctrl.settings.RedirectURI"
|
||||
placeholder="http://yourportainer.com/"
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_redirect_uri"
|
||||
ng-model="$ctrl.settings.RedirectURI"
|
||||
placeholder="http://yourportainer.com/"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group" ng-if="$ctrl.state.provider.name == 'custom' || $ctrl.state.overrideConfiguration">
|
||||
<label for="oauth_user_identifier" class="col-sm-3 col-lg-2 control-label text-left">
|
||||
User Identifier
|
||||
<portainer-tooltip
|
||||
position="bottom"
|
||||
message="Key that identifies the user in the resource server request"
|
||||
position="bottom"
|
||||
message="Key that identifies the user in the resource server request"
|
||||
></portainer-tooltip>
|
||||
</label>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_user_identifier"
|
||||
ng-model="$ctrl.settings.UserIdentifier"
|
||||
placeholder="id"
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_user_identifier"
|
||||
ng-model="$ctrl.settings.UserIdentifier"
|
||||
placeholder="id"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group" ng-if="$ctrl.state.provider.name == 'custom' || $ctrl.state.overrideConfiguration">
|
||||
<label for="oauth_scopes" class="col-sm-3 col-lg-2 control-label text-left">
|
||||
Scopes
|
||||
<portainer-tooltip
|
||||
position="bottom"
|
||||
message="Scopes that are required to obtain the user identifier separated by delimiter if server expects it"
|
||||
position="bottom"
|
||||
message="Scopes that are required to obtain the user identifier separated by delimiter if server expects it"
|
||||
></portainer-tooltip>
|
||||
</label>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_scopes"
|
||||
ng-model="$ctrl.settings.Scopes"
|
||||
placeholder="id,email,name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="oauth_scopes"
|
||||
ng-model="$ctrl.settings.Scopes"
|
||||
placeholder="id,email,name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-if="$ctrl.state.provider.name != 'custom'">
|
||||
<div class="col-sm-12">
|
||||
<a class="small interactive" ng-if="!$ctrl.state.overrideConfiguration" ng-click="$ctrl.state.overrideConfiguration = true;">
|
||||
<i class="fa fa-plus space-right" aria-hidden="true"></i> Override configuration
|
||||
</a>
|
||||
<a class="small interactive" ng-if="$ctrl.state.overrideConfiguration" ng-click="$ctrl.state.overrideConfiguration = false;">
|
||||
<i class="fa fa-minus space-right" aria-hidden="true"></i> Hide advanced options
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
angular.module('portainer.extensions.oauth').component('oauthSettings', {
|
||||
templateUrl: 'app/extensions/oauth/components/oauth-settings/oauth-settings.html',
|
||||
bindings: {
|
||||
settings: '<',
|
||||
settings: '=',
|
||||
teams: '<'
|
||||
}
|
||||
},
|
||||
controller: 'OAuthSettingsController'
|
||||
});
|
||||
|
|
|
@ -120,7 +120,7 @@ angular.module('portainer.app').controller('AuthenticationController', ['$q', '$
|
|||
$state.go('portainer.home');
|
||||
})
|
||||
.catch(function error() {
|
||||
$scope.state.AuthenticationError = 'Failed to authenticate with OAuth2 Provider';
|
||||
$scope.state.AuthenticationError = 'Unable to login via OAuth';
|
||||
$scope.state.isInOAuthProcess = false;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div ng-if="settings.AuthenticationMethod === 1">
|
||||
<div class="col-sm-12 form-section-title">
|
||||
Information
|
||||
|
@ -58,7 +58,7 @@
|
|||
When using internal authentication, Portainer will encrypt user passwords and store credentials locally.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div ng-if="settings.AuthenticationMethod === 2">
|
||||
<div>
|
||||
|
@ -73,7 +73,7 @@
|
|||
<div class="col-sm-12 form-section-title">
|
||||
LDAP configuration
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="ldap_url" class="col-sm-3 col-lg-2 control-label text-left">
|
||||
LDAP Server
|
||||
|
@ -325,6 +325,9 @@
|
|||
<oauth-settings ng-if="isOauthEnabled()" settings="OAuthSettings" teams="teams"></oauth-settings>
|
||||
|
||||
<!-- actions -->
|
||||
<div class="col-sm-12 form-section-title">
|
||||
Actions
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-click="saveSettings()" ng-disabled="state.actionInProgress" button-spinner="state.actionInProgress">
|
||||
|
|
Loading…
Reference in New Issue