Compare commits

...

16 Commits

Author SHA1 Message Date
Robert von Burg 1447bcbc73
[Project] Updated web dependencies 2023-07-04 13:05:44 +02:00
Robert von Burg 82ebdc1d22
[New] Allow to change locale on login form 2023-06-09 16:05:11 +02:00
Robert von Burg ca2f0799e3
[Project] Updated strolch-wc-localize-behavior to 1.1.16 2023-04-21 10:26:49 +02:00
Robert von Burg ce79610705
[Project] Updated web dependencies 2022-07-11 14:02:36 +02:00
Robert von Burg a9acc0f7e0
[Project] Updated web dependencies 2022-05-13 13:14:34 +02:00
Robert von Burg 0b564a18a5
[Minor] larger width of auth form 2022-05-06 08:45:28 +02:00
Robert von Burg 01a1cb316d [Project] Updated strolch-wc-* versions 2022-02-24 16:59:57 +01:00
Robert von Burg ba525aecf9 [New] Also set authToken as authorization header when resetting 2022-02-11 10:50:17 +01:00
Robert von Burg 06a6c398f6 [Minor] use this.async instead of setTimeout 2022-02-11 10:48:16 +01:00
Robert von Burg ffe9eb016a [Project] Updated strolch-wc-* versions 2022-02-10 21:41:06 +01:00
Robert von Burg d847e3ac78 [Minor] Handle version not supplied by server 2021-11-15 09:54:52 +01:00
Robert von Burg 39ca9f7e14 [Project] Update URLs 2021-03-03 14:14:44 +01:00
Robert von Burg bec033e49d [Fix] fix imports 2021-03-03 13:26:05 +01:00
Robert von Burg 7f729b2896 [Major] Implemented password change request 2021-02-23 12:40:10 +01:00
Robert von Burg 0ac8e74fad [Project] Updated strolch-wc-* versions 2020-08-06 12:53:36 +02:00
Robert von Burg fc514af7ff [Project] Updated strolch-wc-* versions 2020-05-12 11:30:42 +02:00
3 changed files with 211 additions and 88 deletions

View File

@ -1,7 +1,7 @@
{
"name": "strolch-wc-auth",
"description": "Strolch WebComponent Auth",
"version": "0.8.0",
"version": "0.9.12",
"authors": ["Robert von Burg"],
"keywords": [
"strolch",
@ -11,16 +11,16 @@
"private": true,
"repository": {
"type": "git",
"url": "git@github.com:4treesCH/strolch-wc-auth.git"
"url": "git@github.com:strolch-li/strolch-wc-auth.git"
},
"license": "https://github.com/4treesCH/strolch-wc-auth/blob/master/LICENSE",
"homepage": "https://github.com/4treesCH/strolch-wc-auth",
"license": "https://github.com/strolch-li/strolch-wc-auth/blob/master/LICENSE",
"homepage": "https://github.com/strolch-li/strolch-wc-auth",
"ignore": [],
"dependencies": {
"strolchjs": "4treesCH/strolchjs#^0.4.0",
"strolch-wc-localize-behavior": "4treesCH/strolch-wc-localize-behavior#^1.1.7",
"strolchjs": "4treesCH/strolchjs#^0.5.3",
"strolch-wc-localize-behavior": "strolch-li/strolch-wc-localize-behavior#^1.1.17",
"polymer": "Polymer/polymer#^1.11.3",
"polymer": "Polymer/polymer#^1.12.0",
"iron-ajax": "PolymerElements/iron-ajax#^1.4.4",
"iron-a11y-keys": "PolymerElements/iron-a11y-keys#^1.0.9",

View File

@ -7,6 +7,7 @@
"reset": "Reset",
"passwordReset": "Password Reset",
"passwordResetDesc": "To reset your password, enter your username",
"passwordChangeRequest": "A password change has been requested",
"passwordResetInitiated": "The reset has been initiated for your account. Please check your e-mail inbox as there should be an e-mail with a reset code. The code in the e-mail will be valid for one hour.",
"passwordResetCode": "Please enter the code here:",
"passwordResetNew": "Type in a new password and please repeat it",
@ -46,6 +47,7 @@
"reset": "Zurücksetzen",
"passwordReset": "Passwort zurücksetzen",
"passwordResetDesc": "Geben Sie Ihren Nutzernamen ein, um ihr Passwort zurückzusetzen",
"passwordChangeRequest": "Das Passwort muss geändert werden",
"passwordResetInitiated": "Der Passwort-Reset wurde eingeleitet. Bitte überprüfen Sie ihren E-Mail Eingang, dieser sollte nun eine E-Mail mit dem Bestätigungs-Code enthalten. Dieser ist für eine Stunde gültig.",
"passwordResetCode": "Bitte geben Sie den Code hier ein:",
"passwordResetNew": "Geben Sie ein neues Passwort ein und wiederholen Sie es",

View File

@ -1,14 +1,16 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-material/paper-material.html">
<link rel="import" href="../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../bower_components/paper-checkbox/paper-checkbox.html">
<link rel="import" href="../../bower_components/paper-input/paper-input.html">
<link rel="import" href="../../bower_components/paper-dialog/paper-dialog.html">
<link rel="import" href="../../bower_components/paper-button/paper-button.html">
<link rel="import" href="../../bower_components/iron-a11y-keys/iron-a11y-keys.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="../../bower_components/strolch-wc-localize-behavior/strolch-wc-localize-behavior.html">
<link rel="import" href="../paper-material/paper-material.html">
<link rel="import" href="../paper-card/paper-card.html">
<link rel="import" href="../paper-checkbox/paper-checkbox.html">
<link rel="import" href="../paper-input/paper-input.html">
<link rel="import" href="../paper-dialog/paper-dialog.html">
<link rel="import" href="../paper-icon-button/paper-icon-button.html">
<link rel="import" href="../paper-listbox/paper-listbox.html">
<link rel="import" href="../paper-button/paper-button.html">
<link rel="import" href="../iron-a11y-keys/iron-a11y-keys.html">
<link rel="import" href="../iron-ajax/iron-ajax.html">
<link rel="import" href="../strolch-wc-localize-behavior/strolch-wc-localize-behavior.html">
<dom-module id="strolch-wc-auth">
@ -28,7 +30,7 @@
}
.centered {
width: 300px;
width: 400px;
margin-left: auto;
margin-right: auto;
margin-top: 3rem;
@ -39,7 +41,8 @@
}
.card-actions {
text-align: right;
display: flex;
justify-content: space-between
}
paper-input {
@ -49,25 +52,29 @@
};
}
#languageDlg paper-listbox {
margin: 0;
}
</style>
<div class="container">
<div id="authForm" class="centered">
<iron-a11y-keys id="a11y" keys="enter" on-keys-pressed="_submitForm"></iron-a11y-keys>
<paper-card heading="{{localize('login')}}">
<paper-card heading="[[localize('login')]]">
<div class="card-content">
<p>{{localize('pleaseLogin', 'appTitle', appTitle)}}</p>
<p>[[localize('pleaseLogin', 'appTitle', appTitle)]]</p>
<paper-input id="usernameInput"
value="{{username}}"
label="{{localize('username')}}"
label="[[localize('username')]]"
required
autofocus="true"
auto-validate></paper-input>
<paper-input id="passwordInput"
value="{{password}}"
label="{{localize('password')}}"
label="[[localize('password')]]"
required
type="password"
on-focus="onFocus"
@ -78,91 +85,115 @@
</template>
<template is="dom-if" if="[[showVersion]]">
<template is="dom-if" if="[[appVersion]]">
<template is="dom-if" if="[[showAppVersion]]">
<p>[[appName]] [[appVersion]] @ [[_getEnv(environment)]]</p>
</template>
<template is="dom-if" if="[[showAppEnvironment]]">
<p>[[appName]] @ [[_getEnv(environment)]]</p>
</template>
</template>
</div>
<div class="card-actions">
<paper-button on-tap="_showResetForm">{{localize('reset')}}</paper-button>
<paper-button on-tap="_submitForm">{{localize('login')}}</paper-button>
<div>
<paper-icon-button icon="icons:language" on-tap="showLanguages"></paper-icon-button>
<paper-dialog id="languageDlg" no-overlap horizontal-align="left" vertical-align="top"
class="aligned-dialog">
<paper-listbox class="dropdown-content" attr-for-selected="value"
selected="{{currentLanguage}}">
<template is="dom-repeat" items="[[languages]]" as="language">
<paper-item value="[[language.locale]]" on-tap="languageSelected">
[[language.name]]
</paper-item>
</template>
</paper-listbox>
</paper-dialog>
</div>
<div>
<paper-button on-tap="_showResetForm">[[localize('reset')]]</paper-button>
<paper-button on-tap="_submitForm">[[localize('login')]]</paper-button>
</div>
</div>
</paper-card>
</div>
<div id="initiateResetForm" class="centered" hidden>
<iron-a11y-keys id="a11y" keys="enter" on-keys-pressed="_initiateReset"></iron-a11y-keys>
<paper-card heading="{{localize('passwordReset')}}">
<paper-card heading="[[localize('passwordReset')]]">
<div class="card-content">
<p>{{localize('passwordResetDesc')}}</p>
<p>[[localize('passwordResetDesc')]]</p>
<paper-input id="usernameResetInput"
value="{{username}}"
label="{{localize('username')}}"
label="[[localize('username')]]"
required
autofocus="true"
auto-validate></paper-input>
</div>
<div class="card-actions">
<paper-button on-tap="_cancelReset">{{localize('cancel')}}</paper-button>
<paper-button on-tap="_initiateReset">{{localize('reset')}}</paper-button>
<paper-button on-tap="_cancelReset">[[localize('cancel')]]</paper-button>
<paper-button on-tap="_initiateReset">[[localize('reset')]]</paper-button>
</div>
</paper-card>
</div>
<div id="resetInitiated" class="centered" hidden>
<iron-a11y-keys id="a11y" keys="enter" on-keys-pressed="_validateChallenge"></iron-a11y-keys>
<paper-card heading="{{localize('passwordReset')}}">
<paper-card heading="[[localize('passwordReset')]]">
<div class="card-content">
<p>{{localize('passwordResetInitiated')}}</p>
<p>{{localize('passwordResetCode')}}</p>
<p>[[localize('passwordResetInitiated')]]</p>
<p>[[localize('passwordResetCode')]]</p>
<paper-input id="codeInput"
bind-value="{{code}}"
label="{{localize('code')}}"
label="[[localize('code')]]"
required
autofocus="true"
auto-validate></paper-input>
</div>
<div class="card-actions">
<paper-button on-tap="_validateChallenge">{{localize('send')}}</paper-button>
<paper-button on-tap="_validateChallenge">[[localize('send')]]</paper-button>
</div>
</paper-card>
</div>
<div id="resetForm" class="centered" hidden>
<iron-a11y-keys id="a11y" keys="enter" on-keys-pressed="_doReset"></iron-a11y-keys>
<paper-card heading="{{localize('passwordReset')}}">
<paper-card heading="[[localize('passwordReset')]]">
<div class="card-content">
<p>{{localize('passwordResetNew')}}</p>
<template is="dom-if" if="[[isPasswordChangeRequested]]">
<p>[[localize('passwordChangeRequest')]]</p>
</template>
<template is="dom-if" if="[[!isPasswordChangeRequested]]">
<p>[[localize('passwordResetNew')]]</p>
</template>
<paper-input id="password1Input"
bind-value="{{password1}}"
label="{{localize('password')}}"
label="[[localize('password')]]"
required
type="password"
on-focus="onFocus"
auto-validate></paper-input>
<paper-input id="password2Input"
bind-value="{{password2}}"
label="{{localize('repeat')}}"
label="[[localize('repeat')]]"
required
type="password"
on-focus="onFocus"
auto-validate></paper-input>
</div>
<div class="card-actions">
<paper-button on-tap="_doReset">{{localize('reset')}}</paper-button>
<paper-button on-tap="_doReset">[[localize('reset')]]</paper-button>
</div>
</paper-card>
</div>
<div id="passwordResetDone" class="centered" hidden>
<iron-a11y-keys id="a11y" keys="enter" on-keys-pressed="_toLogin"></iron-a11y-keys>
<paper-card heading="{{localize('passwordReset')}}">
<paper-card heading="[[localize('passwordReset')]]">
<div class="card-content">
<p>{{localize('passwordResetDone')}}</p>
<p>[[localize('passwordResetDone')]]</p>
</div>
<div class="card-actions">
<paper-button on-tap="_showLoginForm">{{localize('login')}}</paper-button>
<paper-button id="backToLoginBtn" on-tap="_showLoginForm">[[localize('login')]]</paper-button>
</div>
</paper-card>
</div>
@ -195,6 +226,13 @@
method="GET"
on-response="onGetVersionResponse"
on-error="onGetVersionError"></iron-ajax>
<iron-ajax id="ajaxGetSupportedLanguages"
url="[[basePath]]rest/strolch/languages/supported"
content-type="application/json"
handle-as="json"
method="GET"
on-response="onGetSupportedLanguagesResponse"
on-error="onGetSupportedLanguagesError"></iron-ajax>
</template>
<script>
@ -210,14 +248,22 @@
properties: {
basePath: {
type: String,
value: function () {
return './';
}
value: './'
},
localesPath: {
type: String,
value: './locales.json'
},
currentLanguage: {
type: String,
value: function () {
return Strolch.getUserLocale();
}
},
languages: {
type: Array,
value: []
},
appTitle: {
type: String
},
@ -229,11 +275,21 @@
type: Boolean,
value: false
},
showAppVersion: {
type: Boolean,
value: false
},
showAppEnvironment: {
type: Boolean,
value: false
},
appVersion: {
type: String
type: String,
value: null
},
environment: {
type: String
type: String,
value: null
},
username: {
type: String
@ -256,9 +312,23 @@
},
dlgTitle: {
type: String
},
isPasswordChangeRequested: {
type: Boolean,
value: false
}
},
computeShowAppVersion: function (appVersion, environment) {
return appVersion != null && environment != null;
},
computeShowAppEnvironment: function (appVersion, environment) {
return appVersion == null && environment != null;
},
arrayEmpty: function (arr) {
return arr == null || arr.length === 0;
},
ready: function () {
// do nothing
},
@ -271,11 +341,29 @@
this.$.passwordInput.inputElement.select();
},
showLanguages: function (e) {
this.debounce('open-lang-dlg', function () {
var dlg = this.$$('#languageDlg');
dlg.positionTarget = e.target;
dlg.open();
});
// do not bubble the tap event to the wrapping element
e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true);
},
languageSelected: function (e) {
var language = e.model.language;
console.log(language);
Strolch.setUserLocale(language.locale);
sessionStorage.setItem("languageOverride", language.locale);
window.location.reload();
},
reload: function () {
if (this.showVersion) {
if (this.showVersion)
this.$.ajaxGetVersion.generateRequest();
}
this.$.ajaxGetSupportedLanguages.generateRequest();
this.username = '';
this.password = '';
@ -292,15 +380,14 @@
console.log("Validating session...");
}
var that = this;
setTimeout(function () {
that.$.usernameInput.focus();
this.async(function () {
this.$.usernameInput.focus();
}, 100);
},
sessionValidated: function (data) {
sessionValidated: function (e) {
console.log("Session validated.");
var userConfig = data.detail.response;
var userConfig = e.detail.response;
Strolch.setUserConfig(userConfig);
Strolch.sessionVerified = true;
this.fire('strolch-session-valid', {
@ -324,8 +411,6 @@
var keepAliveDays = keepAliveMinutes / 60 / 24;
var delayMin = 14;
var that = this;
if (keepAliveMinutes > 1440) {
// more than a day
@ -339,8 +424,8 @@
} else {
// check again in delayMin min
console.log("Keep alive is " + keepAliveDays + " days and expiring in the future. Delaying refresh for " + delayMin + "m...");
setTimeout(function () {
that.handleKeepAlive(Strolch.getUserConfig());
this.async(function () {
this.handleKeepAlive(Strolch.getUserConfig());
}, delayMin * 60 * 1000);
}
} else if (keepAliveMinutes < 15) {
@ -356,8 +441,8 @@
// check again in delayMin
console.log("Keep alive is " + keepAliveMinutes + " minutes and expiring in " + expiryMin + "m. Delaying refresh for " + delayMin + "m...");
setTimeout(function () {
that.handleKeepAlive(Strolch.getUserConfig());
}, delayMin * 60 * 1000);
this.handleKeepAlive(Strolch.getUserConfig());
}.bind(this), delayMin * 60 * 1000);
} else {
// less than 15 min
@ -378,12 +463,12 @@
console.log('No response handler defined!');
},
_handleAjaxError: function (data) {
_handleAjaxError: function (e) {
var dlgText;
if (data.detail.request.response) {
dlgText = data.detail.request.response.msg;
if (e.detail.request.response) {
dlgText = e.detail.request.response.msg;
} else {
dlgText = data.detail.error;
dlgText = e.detail.error;
}
this.showError(this.dlgTitle, dlgText);
@ -392,7 +477,7 @@
logout: function () {
console.log('Logging out...');
this._ajaxResponse = function (data) {
this._ajaxResponse = function (e) {
console.log('Logged out.');
Strolch.clearStorageData();
};
@ -439,10 +524,19 @@
}
console.log('Authenticating...');
this._ajaxResponse = function (data) {
this._ajaxResponse = function (e) {
if (e.detail.response.usage === "set-password") {
this.authToken = e.detail.response.authToken;
this.isPasswordChangeRequested = true;
this._hideAll();
this.$.resetForm.hidden = false;
this.$.password1Input.focus();
return;
}
console.log('Logged in.');
Strolch.setAuthToken(data.detail.response.authToken);
Strolch.setUserConfig(data.detail.response);
Strolch.setAuthToken(e.detail.response.authToken);
Strolch.setUserConfig(e.detail.response);
location.reload();
};
this.dlgTitle = this.localize('authenticationFailed');
@ -451,6 +545,12 @@
password: btoa(unescape(encodeURIComponent(this.password))),
keepAlive: this.keepAlive
};
var languageOverride = sessionStorage.getItem("languageOverride");
if (languageOverride != null && languageOverride.length !== 0) {
this.$.ajaxAuth.body.languageOverride = languageOverride;
}
this.password = "";
this.$.ajaxAuth.url = this.basePath + 'rest/strolch/authentication';
this.$.ajaxAuth.method = 'POST';
this.$.ajaxAuth.generateRequest();
@ -467,11 +567,13 @@
_showResetForm: function () {
this._hideAll();
this.$.initiateResetForm.hidden = false;
this.$.usernameResetInput.focus();
},
_showLoginForm: function () {
this._hideAll();
this.$.authForm.hidden = false;
this.$.passwordInput.inputElement.select();
},
_cancelReset: function () {
@ -485,11 +587,10 @@
console.log('Initiating reset...');
var that = this;
this._ajaxResponse = function (data) {
that._hideAll();
that.$.resetInitiated.hidden = false;
that.$.codeInput.focus();
this._hideAll();
this.$.resetInitiated.hidden = false;
this.$.codeInput.focus();
};
this.dlgTitle = this.localize('resetFailed');
@ -508,12 +609,11 @@
console.log('Validating challenge...');
var that = this;
this._ajaxResponse = function (data) {
that.authToken = data.detail.response.authToken;
that._hideAll();
that.$.resetForm.hidden = false;
that.$.password1Input.focus();
this.authToken = data.detail.response.authToken;
this._hideAll();
this.$.resetForm.hidden = false;
this.$.password1Input.focus();
};
this.dlgTitle = this.localize('resetFailed');
@ -540,36 +640,57 @@
console.log('Doing reset...');
var that = this;
this._ajaxResponse = function (data) {
that._hideAll();
that.$.passwordResetDone.hidden = false;
this._ajaxResponse = function (e) {
this._hideAll();
this.$.passwordResetDone.hidden = false;
this.$.backToLoginBtn.focus();
};
this.dlgTitle = this.localize('resetFailed');
this.$.ajaxAuth.url = this.basePath + 'rest/strolch/privilege/users/' + this.username + '/password';
this.$.ajaxAuth.headers.authorization = this.authToken;
this.$.ajaxAuth.method = 'PUT';
this.$.ajaxAuth.body = {
password: btoa(unescape(encodeURIComponent(this.password1)))
};
this.password = "";
this.password1 = "";
this.password2 = "";
this.$.ajaxAuth.generateRequest();
},
onGetVersionResponse: function (event) {
var version = event.detail.response;
onGetSupportedLanguagesResponse: function (e) {
if (e.detail.response != null) {
this.languages = e.detail.response;
} else {
this.languages = [];
}
},
onGetSupportedLanguagesError: function (e) {
this.languages = [];
console.log("Failed to get supported languages: " + e.detail.response);
},
onGetVersionResponse: function (e) {
var version = e.detail.response;
this.appName = version.agentVersion.agentName;
this.appVersion = version.appVersion.artifactVersion;
this.environment = version.agentVersion.environment;
this.showAppVersion = this.computeShowAppVersion(this.appVersion, this.environment)
this.showAppEnvironment = this.computeShowAppEnvironment(this.appVersion, this.environment)
Strolch.setAppVersion(version);
sessionStorage.setItem("strolchAppVersion", JSON.stringify(version));
},
onGetVersionError: function (event) {
var readyState = event.detail.request.xhr.readyState;
var status = event.detail.request.xhr.status;
onGetVersionError: function (e) {
var readyState = e.detail.request.xhr.readyState;
var status = e.detail.request.xhr.status;
console.log("Ignoring get version error due to readyState: " + readyState + " / status: " + status);
},
_getEnv: function (environment) {
console.log("environment=" + environment)
if (environment == null)
return "-";
if (environment.indexOf('prod') >= 0) {
return this.localize('production');
} else if (environment.indexOf('test') >= 0) {