mirror of https://github.com/rancher/ui.git
Merge pull request #1908 from westlywright/auth
Azure AD Fixes and Bugs
This commit is contained in:
commit
fa751a9ebf
|
|
@ -57,6 +57,11 @@ $ember-basic-dropdown-content-z-index: 1500;
|
|||
background: $accent-bg;
|
||||
}
|
||||
|
||||
&.lang-select {
|
||||
max-height: 300px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
// Links within the dropdown menu
|
||||
> li > a {
|
||||
display: block;
|
||||
|
|
|
|||
|
|
@ -90,6 +90,12 @@ $tooltip-arrow-color : $tooltip-bg !default;
|
|||
background: lighten($primary-dark, 15%);
|
||||
}
|
||||
|
||||
.icon-vertical-ellipsis {
|
||||
position: relative;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.icon-chevron-down {
|
||||
transition: ease all 350ms;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import Component from '@ember/component';
|
|||
import Errors from 'ui/utils/errors';
|
||||
import layout from './template';
|
||||
import { get, set, observer } from '@ember/object';
|
||||
import { on } from '@ember/object/evented';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
|
|
@ -20,11 +21,6 @@ export default Component.extend({
|
|||
saved: true,
|
||||
errors: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.accessModeChanged();
|
||||
},
|
||||
|
||||
actions: {
|
||||
addAuthorized(principal) {
|
||||
if ( !principal ) {
|
||||
|
|
@ -76,7 +72,7 @@ export default Component.extend({
|
|||
return get(this, 'model.accessMode') !== 'unrestricted';
|
||||
}.property('model.accessMode'),
|
||||
|
||||
accessModeChanged: observer('model.accessMode', function() {
|
||||
accessModeChanged: on('init', observer('model.accessMode', function() {
|
||||
set(this, 'saved',false);
|
||||
|
||||
let allowedPrincipals = get(this, 'model.allowedPrincipalIds') || []; // ['princ_id1://yada']
|
||||
|
|
@ -93,6 +89,6 @@ export default Component.extend({
|
|||
}
|
||||
|
||||
set(this, 'model.allowedPrincipalIds', allowedPrincipals);
|
||||
}),
|
||||
})),
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,127 +1,183 @@
|
|||
import { later } from '@ember/runloop';
|
||||
import { inject as service } from '@ember/service';
|
||||
import Controller from '@ember/controller';
|
||||
import { alias } from '@ember/object/computed';
|
||||
import {
|
||||
get, set, setProperties, computed
|
||||
} from '@ember/object';
|
||||
import C from 'ui/utils/constants';
|
||||
|
||||
export default Controller.extend({
|
||||
access : service(),
|
||||
settings : service(),
|
||||
intl : service(),
|
||||
access: service(),
|
||||
settings: service(),
|
||||
intl: service(),
|
||||
|
||||
confirmDisable : false,
|
||||
errors : null,
|
||||
testing : false,
|
||||
error : null,
|
||||
confirmDisable: false,
|
||||
errors: null,
|
||||
testing: false,
|
||||
error: null,
|
||||
|
||||
loginUsername : null,
|
||||
loginPassword : null,
|
||||
loginUsername: null,
|
||||
loginPassword: null,
|
||||
|
||||
//new
|
||||
azureADConfig: alias('model.azureADConfig'),
|
||||
isEnabled: alias('azureADConfig.enabled'),
|
||||
editing: false,
|
||||
mode: 'global',
|
||||
modeClass: 'span-4',
|
||||
|
||||
numUsers: computed('azureADConfig.allowedPrincipalIds.[]','userType','groupType', function() {
|
||||
return ( get(this, 'azureADConfig.allowedPrincipalIds') || [] ).filter(principal => principal.includes(C.PROJECT.TYPE_AZURE_USER)).get('length');
|
||||
}),
|
||||
|
||||
numGroups: computed('azureADConfig.allowedPrincipalIds.[]','userType','groupType', function() {
|
||||
return ( get(this, 'azureADConfig.allowedPrincipalIds') || [] ).filter(principal => principal.includes(C.PROJECT.TYPE_AZURE_GROUP)).get('length');
|
||||
}),
|
||||
|
||||
actions: {
|
||||
|
||||
edit() {
|
||||
set(this, 'editing', true);
|
||||
},
|
||||
|
||||
toggleMode() {
|
||||
|
||||
if (get(this, 'mode') === 'global') {
|
||||
|
||||
setProperties(this, {
|
||||
mode: 'china',
|
||||
modeClass: 'span-3'
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
setProperties(this, {
|
||||
mode: 'global',
|
||||
modeClass: 'span-4'
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
test: function() {
|
||||
this.send('clearError');
|
||||
|
||||
var model = this.get('model');
|
||||
const model = get(this, 'azureADConfig');
|
||||
const enabled = get(this, 'azureADConfig.enabled');
|
||||
|
||||
model.setProperties({
|
||||
enabled: false,
|
||||
accessMode: 'unrestricted',
|
||||
});
|
||||
|
||||
var errors = model.validationErrors();
|
||||
if ( errors.get('length') )
|
||||
{
|
||||
this.set('errors', errors);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.set('testing', true);
|
||||
model.save().then(() => {
|
||||
this.send('authenticate');
|
||||
}).catch(err => {
|
||||
|
||||
if ( errors.get('length') ) {
|
||||
|
||||
set(this, 'errors', errors);
|
||||
set(this, 'testing', false);
|
||||
model.set('enabled', enabled);
|
||||
|
||||
} else {
|
||||
|
||||
set(this, 'testing', true);
|
||||
|
||||
// delete model.enabled;
|
||||
|
||||
model.doAction('testAndApply', {
|
||||
azureAdConfig: model,
|
||||
enabled: true,
|
||||
username: get(this, 'loginUsername'),
|
||||
password: get(this, 'loginPassword'),
|
||||
}).then( () => {
|
||||
|
||||
this.send('waitAndRefresh');
|
||||
|
||||
}).catch((err) => {
|
||||
|
||||
set(model, 'enabled', enabled);
|
||||
|
||||
this.send('gotError', err);
|
||||
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
authenticate: function() {
|
||||
this.send('clearError');
|
||||
var code = this.get('loginUsername')+':'+this.get('loginPassword');
|
||||
this.get('access').login(code).then(res => {
|
||||
this.send('authenticationSucceeded', res.body);
|
||||
}).catch(err => {
|
||||
this.send('gotError', err);
|
||||
});
|
||||
},
|
||||
|
||||
authenticationSucceeded: function(/*auth*/) {
|
||||
this.send('clearError');
|
||||
|
||||
// Set this to true so the token will be sent with the request
|
||||
this.set('access.enabled', true);
|
||||
|
||||
var model = this.get('model');
|
||||
model.setProperties({
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
model.save().then(() => {
|
||||
this.send('waitAndRefresh');
|
||||
}).catch((err) => {
|
||||
this.set('access.enabled', false);
|
||||
this.send('gotError', err);
|
||||
});
|
||||
},
|
||||
|
||||
waitAndRefresh: function(url) {
|
||||
|
||||
$('#loading-underlay, #loading-overlay').removeClass('hide').show(); // eslint-disable-line
|
||||
|
||||
setTimeout(function() {
|
||||
window.location.href = url || window.location.href;
|
||||
}, 1000);
|
||||
|
||||
},
|
||||
|
||||
promptDisable: function() {
|
||||
this.set('confirmDisable', true);
|
||||
|
||||
set(this, 'confirmDisable', true);
|
||||
|
||||
later(this, function() {
|
||||
this.set('confirmDisable', false);
|
||||
set(this, 'confirmDisable', false);
|
||||
}, 10000);
|
||||
|
||||
},
|
||||
|
||||
gotError: function(err) {
|
||||
if ( err.message )
|
||||
{
|
||||
|
||||
if ( err.message ) {
|
||||
|
||||
this.send('showError', err.message + (err.detail? '('+err.detail+')' : ''));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
} else {
|
||||
|
||||
this.send('showError', 'Error ('+err.status + ' - ' + err.code+')');
|
||||
|
||||
}
|
||||
|
||||
this.set('testing', false);
|
||||
this.set('saving', false);
|
||||
setProperties(this, {
|
||||
testing: false,
|
||||
saving: false,
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
showError: function(msg) {
|
||||
this.set('errors', [msg]);
|
||||
|
||||
set(this, 'errors', [msg]);
|
||||
|
||||
window.scrollY = 0;
|
||||
|
||||
},
|
||||
|
||||
clearError: function() {
|
||||
this.set('errors', null);
|
||||
|
||||
set(this, 'errors', null);
|
||||
|
||||
},
|
||||
|
||||
disable: function() {
|
||||
|
||||
this.send('clearError');
|
||||
|
||||
var model = this.get('model');
|
||||
model.setProperties({
|
||||
enabled: false,
|
||||
username: "",
|
||||
password: "",
|
||||
const model = get(this, 'azureADConfig');
|
||||
|
||||
setProperties(model, {
|
||||
enabled: false,
|
||||
});
|
||||
|
||||
model.save().then(() => {
|
||||
model.doAction('disable').then(() => {
|
||||
|
||||
this.send('waitAndRefresh');
|
||||
|
||||
}).catch((err) => {
|
||||
|
||||
this.send('gotError', err);
|
||||
|
||||
}).finally(() => {
|
||||
this.set('confirmDisable', false);
|
||||
|
||||
set(this, 'confirmDisable', false);
|
||||
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { get } from '@ember/object';
|
||||
import { hash } from 'rsvp';
|
||||
|
||||
export default Route.extend({
|
||||
model: function() {
|
||||
return this.get('globalStore').find('azureadconfig', null, {forceReload: true}).then((collection) => {
|
||||
let obj = collection.get('firstObject');
|
||||
obj.set('accessMode','unrestricted');
|
||||
return obj;
|
||||
});
|
||||
globalStore: service(),
|
||||
|
||||
model() {
|
||||
let gs = get(this, 'globalStore');
|
||||
return hash({
|
||||
azureADConfig: gs.find('authconfig', 'azuread'),
|
||||
principals: gs.all('principal')
|
||||
}).catch( e => e);
|
||||
},
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,117 +1,187 @@
|
|||
<section>
|
||||
{{#if access.enabled}}
|
||||
<p>{{t 'authPage.azuread.header.enabled'}}</p>
|
||||
{{t 'authPage.azuread.subtext.enabled' appName=settings.appName}}
|
||||
{{#if isEnabled}}
|
||||
<p>{{t (concat 'authPage.azuread.header.enabled.' azureADConfig.accessMode)
|
||||
appName=settings.appName
|
||||
groups=numGroups
|
||||
users=numUsers
|
||||
htmlSafe=true
|
||||
}}</p>
|
||||
{{else}}
|
||||
<div class="banner bg-warning">
|
||||
<div class="banner-icon">
|
||||
<span class="icon icon-alert"></span>
|
||||
</div>
|
||||
<div class="banner-message">
|
||||
<p>{{t 'authPage.azuread.header.disabled'}}</p>
|
||||
<p>{{t 'authPage.azuread.header.disabled.label' htmlSafe=true}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<p>{{t 'authPage.azuread.subtext.disabled' appName=settings.appName}}</p>
|
||||
<p>{{t 'authPage.azuread.header.disabled.warning' appName=settings.appName}}</p>
|
||||
{{/if}}
|
||||
</section>
|
||||
|
||||
{{#if access.enabled}}
|
||||
<section class="box mt-30">
|
||||
<h3>{{t 'authPage.azuread.enabled.header' htmlSafe=true}}</h3>
|
||||
<hr/>
|
||||
|
||||
<p>
|
||||
{{t 'authPage.azuread.enabled.warning' appName=settings.appName htmlSafe=true}}
|
||||
</p>
|
||||
{{#accordion-list showExpandAll=false as |al expandFn|}}
|
||||
|
||||
{{#if confirmDisable}}
|
||||
<button class="btn bg-error" {{action "disable"}}>
|
||||
<i class="icon icon-alert"></i> {{t 'authPage.azuread.enabled.reallyDisable'}}
|
||||
</button>
|
||||
{{else}}
|
||||
<button class="btn bg-error" {{action "promptDisable"}}>
|
||||
<i class="icon icon-umbrella"></i> {{t 'authPage.azuread.enabled.promptDisable'}}
|
||||
</button>
|
||||
{{/if}}
|
||||
{{#if isEnabled}}
|
||||
|
||||
</section>
|
||||
{{/if}}
|
||||
{{#accordion-list-item
|
||||
detail=(t 'authPage.azuread.configure.help')
|
||||
expand=(action expandFn)
|
||||
expandAll=al.expandAll
|
||||
expandOnInit=true
|
||||
expanded=true
|
||||
showExpand=false
|
||||
title=(t 'authPage.github.authenticated.header.text')
|
||||
}}
|
||||
|
||||
{{#unless access.enabled}}
|
||||
<section class="box mt-30">
|
||||
<h3>{{t 'authPage.azuread.configure.header'}}</h3>
|
||||
<hr/>
|
||||
<section class="">
|
||||
<div class="clearfix">
|
||||
<div class="pull-right">
|
||||
<button class="btn btn-sm bg-primary" {{action "edit"}}>
|
||||
{{t 'generic.edit'}}
|
||||
</button>
|
||||
<button class="btn btn-sm right-divider-btn bg-error" {{action "disable"}}>
|
||||
{{t 'authPage.azuread.enabled.promptDisable'}}
|
||||
</button>
|
||||
</div>
|
||||
<span class="help-block">{{t 'authPage.azuread.configure.help'}}</span>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col span-12">
|
||||
<h3>{{t 'authPage.azuread.enabled.general.header'}}</h3>
|
||||
<div>
|
||||
<b>{{t 'authPage.azuread.configure.tenantId.label'}}: </b> <span class="text-muted">{{azureADConfig.tenantId}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<b>{{t 'authPage.azuread.configure.clientId.label'}}: </b> <span class="text-muted">{{azureADConfig.clientId}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<b>{{t 'authPage.azuread.configure.domain.label'}}: </b> <span class="text-muted">{{azureADConfig.domain}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-4">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.configure.tenantId.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=model.tenantId placeholder=(t 'authPage.azuread.configure.tenantId.placeholder') classNames="form-control"}}
|
||||
<p class="help-block">{{t 'authPage.azuread.configure.tenantId.help'}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.configure.clientId.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=model.clientId placeholder=(t 'authPage.azuread.configure.clientId.placeholder') classNames="form-control"}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.configure.domain.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=model.domain placeholder=(t 'authPage.azuread.configure.domain.placeholder') classNames="form-control"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.configure.adminAccountUsername.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=model.adminAccountUsername placeholder=(t 'authPage.azuread.configure.adminAccountUsername.placeholder') classNames="form-control"}}
|
||||
<p class="help-block">{{t 'authPage.azuread.configure.adminAccountUsername.help'}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.configure.adminAccountPassword.label'}}{{field-required}}</label>
|
||||
{{input type="password" value=model.adminAccountPassword classNames="form-control"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{#accordion-list-item
|
||||
classNames="mt-30"
|
||||
detail=(t 'siteAccess.helpText' appName=settings.appName htmlSafe=true)
|
||||
expand=(action expandFn)
|
||||
expandAll=al.expandAll
|
||||
expandOnInit=true
|
||||
expanded=true
|
||||
showExpand=false
|
||||
title=(t 'siteAccess.header')
|
||||
}}
|
||||
|
||||
<section class="box mt-30">
|
||||
<h3>{{t 'authPage.azuread.test.header'}}</h3>
|
||||
<hr/>
|
||||
<p class="text-info">{{t 'authPage.azuread.test.help'}}</p>
|
||||
{{top-errors errors=errors}}
|
||||
{{site-access
|
||||
model=azureADConfig
|
||||
principals=model.principals
|
||||
collection='siteAccess.organizations'
|
||||
}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-4">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.test.username.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=loginUsername prompt=(t 'authPage.azuread.test.username.placeholder') classNames="form-control"}}
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{/if}}
|
||||
|
||||
|
||||
{{#if (or (not isEnabled) editing)}}
|
||||
{{#accordion-list-item
|
||||
classNames="mt-30"
|
||||
detail=(t 'authPage.azuread.configure.help')
|
||||
expand=(action expandFn)
|
||||
expandAll=al.expandAll
|
||||
expandOnInit=true
|
||||
expanded=true
|
||||
showExpand=false
|
||||
title=(t 'authPage.azuread.configure.header')
|
||||
}}
|
||||
|
||||
<section>
|
||||
<div class="row">
|
||||
<div class="pull-right btn-group no-inline-space p-0">
|
||||
<button class="btn btn-link btn-sm {{if (eq mode 'global') 'bg-primary' 'bg-deafult'}}" {{action 'toggleMode'}}>Global</button>
|
||||
<button class="btn btn-link btn-sm bg-defualt {{if (eq mode 'china') 'bg-primary' 'bg-deafult'}}" {{action 'toggleMode'}}>China</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.test.password.label'}}{{field-required}}</label>
|
||||
{{input type="password" value=loginPassword classNames="form-control"}}
|
||||
<hr/>
|
||||
|
||||
<div class="row">
|
||||
<div class="col {{modeClass}}">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.configure.tenantId.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=azureADConfig.tenantId placeholder=(t 'authPage.azuread.configure.tenantId.placeholder') classNames="form-control"}}
|
||||
<p class="help-block">{{t 'authPage.azuread.configure.tenantId.help'}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col {{modeClass}}">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.configure.clientId.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=azureADConfig.clientId placeholder=(t 'authPage.azuread.configure.clientId.placeholder') classNames="form-control"}}
|
||||
</div>
|
||||
</div>
|
||||
{{#unless (eq mode 'global')}}
|
||||
<div class="col span-3">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.configure.clientSecret.label'}}{{field-required}}</label>
|
||||
{{input type="password" value=azureADConfig.clientSecret placeholder=(t 'authPage.azuread.configure.clientSecret.placeholder') classNames="form-control"}}
|
||||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
<div class="col {{modeClass}}">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.configure.domain.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=azureADConfig.domain placeholder=(t 'authPage.azuread.configure.domain.placeholder') classNames="form-control"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5"> </label>
|
||||
<button class="btn bg-primary mt-25" style="height: 38px; line-height: 28px;" {{action "test"}}>
|
||||
{{#if testing}}
|
||||
<i class="icon icon-spinner icon-spin"></i> {{t 'authPage.azuread.test.post'}}
|
||||
{{else}}
|
||||
{{t 'authPage.azuread.test.pre'}}
|
||||
{{/if}}
|
||||
</button>
|
||||
</section>
|
||||
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#accordion-list-item
|
||||
classNames="mt-30"
|
||||
detail=(t 'authPage.azuread.test.help')
|
||||
expand=(action expandFn)
|
||||
expandAll=al.expandAll
|
||||
expandOnInit=true
|
||||
expanded=true
|
||||
showExpand=false
|
||||
title=(t 'authPage.azuread.test.header')
|
||||
}}
|
||||
|
||||
<section>
|
||||
{{top-errors errors=errors}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.test.username.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=loginUsername prompt=(t 'authPage.azuread.test.username.placeholder') classNames="form-control"}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<div class="inline-form">
|
||||
<label class="acc-label pb-5">{{t 'authPage.azuread.test.password.label'}}{{field-required}}</label>
|
||||
{{input type="password" value=loginPassword classNames="form-control"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{/unless}}
|
||||
<div class="row mt-10">
|
||||
<div class="inline-form">
|
||||
<button class="btn bg-primary" style="display: block;margin: 0 auto;" {{action "test"}}>
|
||||
{{#if testing}}
|
||||
<i class="icon icon-spinner icon-spin"></i> {{t 'authPage.azuread.test.post'}}
|
||||
{{else}}
|
||||
{{t 'authPage.azuread.test.pre'}}
|
||||
{{/if}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{/accordion-list-item}}
|
||||
{{/if}}
|
||||
|
||||
{{/accordion-list}}
|
||||
|
|
@ -10,9 +10,8 @@ export default Controller.extend({
|
|||
drivers: computed(function() {
|
||||
return [
|
||||
{route: 'security.authentication.activedirectory', label: 'Active Directory', css: 'activedirectory', available: this.hasRecord('activedirectoryconfig') },
|
||||
// {route: 'security.authentication.azuread', label: 'Azure AD', css: 'azuread', available: this.hasRecord('azureadconfig') },
|
||||
{route: 'security.authentication.azuread', label: 'Azure AD', css: 'azuread', available: this.hasRecord('azureadconfig') },
|
||||
{route: 'security.authentication.github', label: 'GitHub', css: 'github', available: this.hasRecord('githubconfig') },
|
||||
// {route: 'security.authentication.localauth', label: 'Local', css: 'local', available: this.hasRecord('localconfig') }, // always on
|
||||
// {route: 'security.authentication.openldap', label: 'OpenLDAP', css: 'openldap', available: this.hasRecord('openldapconfig') },
|
||||
// {route: 'security.authentication.shibboleth', label: 'Shibboleth', css: 'shibboleth', available: this.hasRecord('shibbolethconfig') },
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,24 +1,72 @@
|
|||
import { get, set, computed } from '@ember/object';
|
||||
import { get, set, computed, setProperties } from '@ember/object';
|
||||
import { next } from '@ember/runloop';
|
||||
import { inject as service } from '@ember/service';
|
||||
import Component from '@ember/component';
|
||||
import C from 'ui/utils/constants';
|
||||
|
||||
export default Component.extend({
|
||||
access: service(),
|
||||
access: service(),
|
||||
cookies: service(),
|
||||
isCaas: computed('app.mode', function() {
|
||||
return this.get('app.mode') === 'caas' ? true : false;
|
||||
}),
|
||||
waiting: null,
|
||||
intl: service(),
|
||||
|
||||
username: null,
|
||||
waiting: null,
|
||||
username: null,
|
||||
rememberUsername: false,
|
||||
password: null,
|
||||
shown: false,
|
||||
provider: null,
|
||||
password: null,
|
||||
shown: false,
|
||||
provider: null,
|
||||
readableProvider: null,
|
||||
onlyLocal: null,
|
||||
onlyLocal: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
let username = null;
|
||||
|
||||
if (get(this, 'provider') === 'local') {
|
||||
|
||||
username = get(this, `cookies.${C.COOKIE.USERNAME}`);
|
||||
|
||||
} else {
|
||||
|
||||
username = get(this, `cookies.${get(this, 'provider').toUpperCase()}-USERNAME`);
|
||||
|
||||
}
|
||||
|
||||
if ( username ) {
|
||||
setProperties(this, {
|
||||
username: username,
|
||||
rememberUsername: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (get(this, 'provider') && !get(this,'onlyLocal')) {
|
||||
|
||||
let pv = null;
|
||||
|
||||
switch(get(this, 'provider')) {
|
||||
|
||||
case 'activedirectory':
|
||||
pv = get(this, 'intl').t('loginPage.readableProviders.ad');
|
||||
break;
|
||||
|
||||
case 'azuread':
|
||||
pv = get(this, 'intl').t('loginPage.readableProviders.azureAd');
|
||||
break;
|
||||
|
||||
case 'local':
|
||||
default:
|
||||
pv = get(this, 'intl').t('loginPage.readableProviders.local');
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
set(this, 'readableProvider', pv);
|
||||
|
||||
// console.log(this.get('provider'));
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
actions: {
|
||||
showLocal() {
|
||||
|
|
@ -56,39 +104,9 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
var username = null;
|
||||
if (get(this, 'provider') === 'local') {
|
||||
username = get(this, `cookies.${C.COOKIE.USERNAME}`);
|
||||
} else {
|
||||
username = get(this, `cookies.${get(this, 'provider').toUpperCase()}-USERNAME`);
|
||||
}
|
||||
|
||||
if ( username ) {
|
||||
set(this, 'username', username);
|
||||
set(this, 'rememberUsername', true);
|
||||
}
|
||||
|
||||
if (get(this, 'provider') && !get(this,'onlyLocal')) {
|
||||
let pv = null;
|
||||
switch(get(this, 'provider')) {
|
||||
case 'activedirectory':
|
||||
pv = 'Active Directory';
|
||||
break;
|
||||
case 'local':
|
||||
default:
|
||||
pv = 'a Local User';
|
||||
break;
|
||||
}
|
||||
|
||||
set(this, 'readableProvider', pv);
|
||||
|
||||
// console.log(this.get('provider'));
|
||||
}
|
||||
|
||||
},
|
||||
isCaas: computed('app.mode', function() {
|
||||
return this.get('app.mode') === 'caas' ? true : false;
|
||||
}),
|
||||
|
||||
focusSomething() {
|
||||
if ( this.isDestroyed || this.isDestroying ) {
|
||||
|
|
|
|||
|
|
@ -101,6 +101,9 @@ export default Controller.extend({
|
|||
case 'activedirectory':
|
||||
this.toggleProperty('adWaiting');
|
||||
break;
|
||||
case 'azuread':
|
||||
this.toggleProperty('azureadWaiting');
|
||||
break;
|
||||
case 'shibboleth':
|
||||
this.toggleProperty('shibbolethWaiting');
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,16 @@
|
|||
}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isAzureAd}}
|
||||
{{login-user-pass
|
||||
action="authenticate"
|
||||
classNames="row"
|
||||
provider="azuread"
|
||||
shown=true
|
||||
waiting=azureadWaiting
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isLocal}}
|
||||
{{login-user-pass
|
||||
action="authenticate"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Component from '@ember/component';
|
||||
import layout from './template';
|
||||
import { inject as service } from '@ember/service'
|
||||
import { computed } from '@ember/object';
|
||||
import { computed, get } from '@ember/object';
|
||||
|
||||
|
||||
export default Component.extend({
|
||||
|
|
@ -17,16 +17,29 @@ export default Component.extend({
|
|||
size: 'xs',
|
||||
|
||||
actions: {
|
||||
|
||||
clickedAction: function(actionName) {
|
||||
this.get('resourceActions').triggerAction(actionName);
|
||||
},
|
||||
|
||||
closeLater(dd) {
|
||||
dd.actions.close();
|
||||
return true;
|
||||
},
|
||||
|
||||
preload() {
|
||||
this.get('resourceActions').setActionItems(this.get('model'), this.get('context'));
|
||||
}
|
||||
},
|
||||
|
||||
actionsOpen() {
|
||||
get(this, 'tooltipService').set('childOpened', true);
|
||||
},
|
||||
|
||||
actionsClosed() {
|
||||
get(this, 'tooltipService').set('childOpened', false);
|
||||
get(this, 'tooltipService').hide();
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
sizeClass: computed('size', function() {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
{{#basic-dropdown as |dd|}}
|
||||
{{#basic-dropdown
|
||||
horizontalPosition="right"
|
||||
verticalPosition="below"
|
||||
onOpen=(action 'actionsOpen')
|
||||
onClose=(action 'actionsClosed')
|
||||
as |dd|
|
||||
}}
|
||||
|
||||
{{#dd.trigger
|
||||
ariaLabel=(t 'generic.moreActions')
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@
|
|||
localizedPrompt=true
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'clusterNew.azureaks.dns.label'}}</label>
|
||||
{{input type="text" value=config.masterDnsPrefix classNames="form-control" placeholder=(t 'clusterNew.azureaks.dns.placeholder')}}
|
||||
</div>
|
||||
</div>
|
||||
{{/accordion-list-item}}
|
||||
{{#accordion-list-item
|
||||
|
|
@ -70,7 +74,7 @@
|
|||
{{t 'generic.na'}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{input type="text" value=config.clientSecret classNames="form-control" placeholder=(t 'clusterNew.azureaks.clientSecret.placeholder')}}
|
||||
{{input type="password" value=config.clientSecret classNames="form-control" placeholder=(t 'clusterNew.azureaks.clientSecret.placeholder')}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -111,7 +115,7 @@
|
|||
{{/if}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'clusterNew.azureaks.resourceGroup.label'}}</label>
|
||||
<label class="acc-label">{{t 'clusterNew.azureaks.resourceGroup.label'}}{{field-required}}</label>
|
||||
{{#if editing}}
|
||||
<div>
|
||||
{{config.resourceGroup}}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
{{#basic-dropdown
|
||||
verticalPosition="above"
|
||||
horizontalPosition="right"
|
||||
as |dd|
|
||||
}}
|
||||
|
|
@ -10,7 +9,7 @@
|
|||
<i class="icon icon-globe"></i> {{selectedLabel}} <i class="icon icon-chevron-down"></i>
|
||||
{{/dd.trigger}}
|
||||
|
||||
{{#dd.content class="text-right"}}
|
||||
{{#dd.content class="text-right lang-select"}}
|
||||
{{#if settings.isRancher}}
|
||||
<li><a href="http://translate.rancher.com" target="_blank" rel="noopener nofollow">{{t 'languageContribute'}}</a></li>
|
||||
<li class="divider"></li>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,44 @@
|
|||
import Mixin from '@ember/object/mixin';
|
||||
import { cancel, later } from '@ember/runloop';
|
||||
import { get, set } from '@ember/object';
|
||||
|
||||
export default Mixin.create({
|
||||
closeTimer: null,
|
||||
|
||||
actions: {
|
||||
prevent() {
|
||||
return false;
|
||||
},
|
||||
|
||||
open(dropdown) {
|
||||
if (this.closeTimer) {
|
||||
cancel(this.closeTimer);
|
||||
this.closeTimer = null;
|
||||
const ct = get(this, 'closeTimer');
|
||||
|
||||
console.log('open closeTimer: ', this.closeTimer, get(dropdown, 'uniqueId'));
|
||||
if (ct) {
|
||||
|
||||
cancel(ct);
|
||||
set(this, 'closeTimer', null);
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
dropdown.actions.open();
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
closeLater(dropdown) {
|
||||
this.closeTimer = later(() => {
|
||||
this.closeTimer = null;
|
||||
|
||||
set(this, 'closeTimer', later(() => {
|
||||
|
||||
dropdown.actions.close();
|
||||
}, 200);
|
||||
set(this, 'closeTimer', null);
|
||||
|
||||
}, 200));
|
||||
console.log('close closeTimer: ', this.closeTimer, get(dropdown, 'uniqueId'));
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,19 +1,24 @@
|
|||
import { later, cancel } from '@ember/runloop';
|
||||
import Service, { inject as service } from '@ember/service';
|
||||
import { get } from '@ember/object';
|
||||
|
||||
const DELAY = 250;
|
||||
|
||||
export default Service.extend({
|
||||
mouseLeaveTimer: null,
|
||||
requireClick: false,
|
||||
tooltipOpts: null,
|
||||
app: service(),
|
||||
|
||||
mouseLeaveTimer: null,
|
||||
requireClick: false,
|
||||
tooltipOpts: null,
|
||||
openedViaContextClick: false,
|
||||
app: service(),
|
||||
childOpened: false,
|
||||
|
||||
startTimer() {
|
||||
|
||||
this.set('mouseLeaveTimer', later(() => {
|
||||
this.hide();
|
||||
}, DELAY));
|
||||
|
||||
},
|
||||
|
||||
cancelTimer() {
|
||||
|
|
@ -21,13 +26,19 @@ export default Service.extend({
|
|||
},
|
||||
|
||||
hide() {
|
||||
this.set('tooltipOpts', null);
|
||||
|
||||
if (!get(this, 'childOpened')) {
|
||||
this.set('tooltipOpts', null);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
leave() {
|
||||
if ( !this.get('requireClick') )
|
||||
{
|
||||
|
||||
if ( !this.get('requireClick') ) {
|
||||
this.startTimer();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -449,36 +449,62 @@ authPage:
|
|||
post: Waiting to hear back from GitHub
|
||||
azuread:
|
||||
header:
|
||||
enabled: 'Azure AD Authentication is <b>enabled</b>'
|
||||
disabled: 'Azure AD Authentication is not configured'
|
||||
subtext:
|
||||
enabled: '{appName} is configured to allow access to accounts in Azure AD'
|
||||
disabled: '{appName} can be configured to restrict access to a set of accounts defined in the {appName} database. This is not currently set up, so anybody that reach this page (or the API) has full control over the system.'
|
||||
enabled:
|
||||
label: "Azure AD is enabled"
|
||||
required: |
|
||||
{appName} is configured to allow access to {groups, plural,
|
||||
=0 {no groups}
|
||||
=1 {# group}
|
||||
other {# groups}
|
||||
} and {users, plural,
|
||||
=0 {no users}
|
||||
=1 {# user}
|
||||
other {# users}
|
||||
}.
|
||||
restricted: |
|
||||
{appName} is configured to allow access to environment members, {groups, plural,
|
||||
=0 {no groups}
|
||||
=1 {# group}
|
||||
other {# groups}
|
||||
} and {users, plural,
|
||||
=0 {no users}
|
||||
=1 {# user}
|
||||
other {# users}
|
||||
}.
|
||||
unrestricted: "{appName} is configured to allow access to any Azure AD user."
|
||||
disabled:
|
||||
label: "Azure AD is not configured"
|
||||
warning: "{appName} can be configured to restrict access to a set of Azure AD users and groups"
|
||||
enabled:
|
||||
header: 'Danger Zone™'
|
||||
warning: '<b class="text-danger">Caution:</b> Disabling access control will give complete control over {appName} to anyone that can reach this page or the API.'
|
||||
reallyDisable: 'Are you sure? Click again to really disable access control'
|
||||
promptDisable: Disable access control
|
||||
promptDisable: Disable Azure AD
|
||||
general:
|
||||
header: General
|
||||
configure:
|
||||
header: '1. Configure Azure AD Account'
|
||||
tenantId:
|
||||
label: Tenant ID
|
||||
placeholder: A long UUID string
|
||||
help: From the Azure AD portal
|
||||
clientId:
|
||||
label: Client ID
|
||||
placeholder: A long UUID string
|
||||
domain:
|
||||
label: Domain
|
||||
placeholder: e.g. youcompany.onmicrosoft.com
|
||||
header: 'Configure Azure AD Account'
|
||||
help: Enter the Tenant ID, Client ID, and Admin user details to connect to your Azure AD auth account.
|
||||
adminAccountUsername:
|
||||
label: Admin Account Username
|
||||
placeholder: e.g. rancher-admin
|
||||
help: A user that can read information about other users
|
||||
adminAccountPassword:
|
||||
label: Admin Account Password
|
||||
clientId:
|
||||
label: Client ID
|
||||
placeholder: A long UUID string
|
||||
clientSecret:
|
||||
label: Client Secret
|
||||
placeholder: Your Client Secret
|
||||
domain:
|
||||
label: Domain
|
||||
placeholder: e.g. youcompany.onmicrosoft.com
|
||||
tenantId:
|
||||
label: Tenant ID
|
||||
placeholder: A long UUID string
|
||||
help: From the Azure AD portal
|
||||
test:
|
||||
header: '2. Test and enable authentication'
|
||||
header: 'Test and enable authentication'
|
||||
help: 'Check that everything is configured correctly by testing authentication with your account:'
|
||||
username:
|
||||
label: Login Username
|
||||
|
|
@ -1076,6 +1102,10 @@ loginPage:
|
|||
error:
|
||||
authFailedCreds: "Logging in failed: Check credentials, or your account may not be authorized to log in."
|
||||
authFailed: "Logging in failed: Your account may not be authorized to log in."
|
||||
readableProviders:
|
||||
ad: Active Directory
|
||||
azureAd: Azure AD
|
||||
local: a Local User
|
||||
|
||||
machinePage:
|
||||
header: Node Drivers
|
||||
|
|
@ -1757,6 +1787,9 @@ clusterNew:
|
|||
prompt: Choose a size...
|
||||
diskSizeGb:
|
||||
label: OS Disk Size
|
||||
dns:
|
||||
label: DNS Prfix
|
||||
placeholder: "e.g. example"
|
||||
ssh:
|
||||
label: SSH Public Key
|
||||
security:
|
||||
|
|
@ -4763,7 +4796,7 @@ nodeDriver:
|
|||
region:
|
||||
label: Region
|
||||
aliyunecs:
|
||||
accountSection:
|
||||
accountSection:
|
||||
label: 1. Account Access
|
||||
detail: API Keys will be used to launch Aliyun ECS Instances.
|
||||
next: "Next: Authenticate & Config network options"
|
||||
|
|
@ -4796,7 +4829,7 @@ nodeDriver:
|
|||
aliyunSLB:
|
||||
label: Aliyun SLB ID
|
||||
placeholder: Aliyun SLB ID
|
||||
storageSection:
|
||||
storageSection:
|
||||
label: Storage
|
||||
detail: Configure the storage for the instances that will be created by this template.
|
||||
next: "Next: Config Aliyun ECS Instance options"
|
||||
|
|
@ -4837,7 +4870,7 @@ nodeDriver:
|
|||
placeholder: Private IP in Private Network
|
||||
privateAddressOnly:
|
||||
label: Private Address Only
|
||||
securitySection:
|
||||
securitySection:
|
||||
label: Security
|
||||
detail: Choose the security groups that will be applied to Instances
|
||||
securityGroup:
|
||||
|
|
|
|||
|
|
@ -2604,9 +2604,9 @@ elliptic@^6.0.0:
|
|||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.0"
|
||||
|
||||
ember-api-store@^2.6.6:
|
||||
version "2.6.6"
|
||||
resolved "https://registry.yarnpkg.com/ember-api-store/-/ember-api-store-2.6.6.tgz#c405ce94f21ca7c5d80568cbf33f99b42403dce0"
|
||||
ember-api-store@2.6.8:
|
||||
version "2.6.8"
|
||||
resolved "https://registry.yarnpkg.com/ember-api-store/-/ember-api-store-2.6.8.tgz#fdcc950ea1c8cab7633e0480eb5061534c650d0c"
|
||||
dependencies:
|
||||
broccoli-file-creator "^1.1.1"
|
||||
ember-cli-babel "^6.8.2"
|
||||
|
|
|
|||
Loading…
Reference in New Issue