mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[PRODENG-211] integrate JS-API with monorepo (part 1) (#9081)
* integrate JS-API with monorepo * [ci:force] fix token issue [ci:force] migrate docs folder [ci:force] clean personal tokens * [ci:force] gha workflow support * [ci:force] npm publish target * fix js-api test linting * [ci:force] fix test linting, mocks, https scheme * [ci:force] fix https scheme * [ci:force] typescript mappings * [ci:force] update scripts * lint fixes * linting fixes * fix linting * [ci:force] linting fixes * linting fixes * [ci:force] remove js-api upstream and corresponding scripts * [ci:force] jsdoc fixes * fix jsdoc linting * [ci:force] jsdoc fixes * [ci:force] jsdoc fixes * jsdoc fixes * jsdoc fixes * jsdoc fixes * [ci:force] fix jsdoc * [ci:force] reduce code duplication * replace 'chai' expect with node.js assert * replace 'chai' expect with node.js assert * [ci:force] remove chai and chai-spies for js-api testing * [ci:force] cleanup and fix imports * [ci:force] fix linting * [ci:force] fix unit test * [ci:force] fix sonar linting findings * [ci:force] switch activiti api models to interfaces (-2.5% reduction of bundle) * [ci:force] switch activiti api models to interfaces * [ci:force] switch AGS api models to interfaces * [ci:force] switch AGS api models to interfaces * [ci:force] switch search api models to interfaces * [ci:force] switch content api models to interfaces where applicable
This commit is contained in:
26
lib/js-api/src/authentication/authentication.ts
Normal file
26
lib/js-api/src/authentication/authentication.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BasicAuth } from './basicAuth';
|
||||
import { Oauth2 } from './oauth2';
|
||||
|
||||
export interface Authentication {
|
||||
basicAuth?: BasicAuth;
|
||||
oauth2?: Oauth2;
|
||||
cookie?: string;
|
||||
type?: string;
|
||||
}
|
22
lib/js-api/src/authentication/basicAuth.ts
Normal file
22
lib/js-api/src/authentication/basicAuth.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface BasicAuth {
|
||||
username?: string;
|
||||
password?: string;
|
||||
ticket?: string;
|
||||
}
|
215
lib/js-api/src/authentication/contentAuth.ts
Normal file
215
lib/js-api/src/authentication/contentAuth.ts
Normal file
@@ -0,0 +1,215 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import ee from 'event-emitter';
|
||||
import { AuthenticationApi, TicketBody } from '../api/auth-rest-api';
|
||||
import { AlfrescoApiClient } from '../alfrescoApiClient';
|
||||
import { AlfrescoApiConfig } from '../alfrescoApiConfig';
|
||||
import { Authentication } from './authentication';
|
||||
import { Storage } from '../storage';
|
||||
import { AlfrescoApiType } from '../to-deprecate/alfresco-api-type';
|
||||
import { HttpClient } from '../api-clients/http-client.interface';
|
||||
|
||||
export class ContentAuth extends AlfrescoApiClient {
|
||||
ticketStorageLabel: string;
|
||||
ticket: string;
|
||||
|
||||
authApi: AuthenticationApi;
|
||||
|
||||
constructor(config: AlfrescoApiConfig, alfrescoApi: AlfrescoApiType, httpClient?: HttpClient) {
|
||||
super(undefined, httpClient);
|
||||
this.className = 'ContentAuth';
|
||||
this.storage = Storage.getInstance();
|
||||
this.storage.setDomainPrefix(config.domainPrefix);
|
||||
|
||||
this.setConfig(config);
|
||||
|
||||
this.authApi = new AuthenticationApi(alfrescoApi);
|
||||
}
|
||||
|
||||
setConfig(config: AlfrescoApiConfig) {
|
||||
this.config = config;
|
||||
|
||||
this.basePath = this.config.hostEcm + '/' + this.config.contextRoot + '/api/-default-/public/authentication/versions/1'; //Auth Call
|
||||
|
||||
this.ticketStorageLabel = 'ticket-ECM';
|
||||
|
||||
if (this.config.ticketEcm) {
|
||||
this.setTicket(config.ticketEcm);
|
||||
} else if (this.storage.getItem(this.ticketStorageLabel)) {
|
||||
this.setTicket(this.storage.getItem(this.ticketStorageLabel));
|
||||
}
|
||||
}
|
||||
|
||||
changeHost() {
|
||||
this.basePath = this.config.hostEcm + '/' + this.config.contextRoot + '/api/-default-/public/authentication/versions/1'; //Auth Call
|
||||
this.ticket = undefined;
|
||||
}
|
||||
|
||||
saveUsername(username: string) {
|
||||
if (this.storage.supportsStorage()) {
|
||||
this.storage.setItem('ACS_USERNAME', username);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* login Alfresco API
|
||||
*
|
||||
* @param username Username to login
|
||||
* @param password Password to login
|
||||
* @returns A promise that returns {new authentication ticket} if resolved and {error} if rejected.
|
||||
*/
|
||||
login(username: string, password: string): Promise<string> {
|
||||
this.authentications.basicAuth.username = username;
|
||||
this.authentications.basicAuth.password = password;
|
||||
|
||||
const loginRequest = new TicketBody({
|
||||
userId: this.authentications.basicAuth.username,
|
||||
password: this.authentications.basicAuth.password
|
||||
});
|
||||
|
||||
const promise: any = new Promise<string>((resolve, reject) => {
|
||||
this.authApi
|
||||
.createTicket(loginRequest)
|
||||
.then((data) => {
|
||||
this.saveUsername(username);
|
||||
this.setTicket(data.entry.id);
|
||||
promise.emit('success');
|
||||
this.emit('logged-in');
|
||||
resolve(data.entry.id);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.saveUsername('');
|
||||
if (error.status === 401) {
|
||||
promise.emit('unauthorized');
|
||||
} else if (error.status === 403) {
|
||||
promise.emit('forbidden');
|
||||
} else {
|
||||
promise.emit('error');
|
||||
}
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
||||
ee(promise); // jshint ignore:line
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate the ticket present in this.config.ticket against the server
|
||||
*
|
||||
* @returns A promise that returns if resolved and {error} if rejected.
|
||||
*/
|
||||
validateTicket(): Promise<string> {
|
||||
this.setTicket(this.config.ticketEcm);
|
||||
|
||||
const promise: any = new Promise<string>((resolve, reject) => {
|
||||
this.authApi.validateTicket().then(
|
||||
(data) => {
|
||||
this.setTicket(data.entry.id);
|
||||
promise.emit('success');
|
||||
this.emit('logged-in');
|
||||
resolve(data.entry.id);
|
||||
},
|
||||
(error) => {
|
||||
if (error.status === 401) {
|
||||
promise.emit('unauthorized');
|
||||
}
|
||||
promise.emit('error');
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
ee(promise); // jshint ignore:line
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* logout Alfresco API
|
||||
*
|
||||
* @returns A promise that returns { authentication ticket} if resolved and {error} if rejected.
|
||||
*/
|
||||
logout(): Promise<void> {
|
||||
this.saveUsername('');
|
||||
const promise: any = new Promise<void>((resolve, reject) => {
|
||||
this.authApi.deleteTicket().then(
|
||||
() => {
|
||||
promise.emit('logout');
|
||||
this.invalidateSession();
|
||||
resolve();
|
||||
},
|
||||
(error) => {
|
||||
if (error.status === 401) {
|
||||
promise.emit('unauthorized');
|
||||
}
|
||||
promise.emit('error');
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
ee(promise); // jshint ignore:line
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current Ticket
|
||||
*/
|
||||
setTicket(ticket: string) {
|
||||
this.authentications.basicAuth.username = 'ROLE_TICKET';
|
||||
this.authentications.basicAuth.password = ticket;
|
||||
this.config.ticketEcm = ticket;
|
||||
this.storage.setItem(this.ticketStorageLabel, ticket);
|
||||
this.ticket = ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current Ticket
|
||||
*
|
||||
* @returns ticket value
|
||||
*/
|
||||
getTicket(): string {
|
||||
return this.ticket;
|
||||
}
|
||||
|
||||
invalidateSession() {
|
||||
this.storage.removeItem(this.ticketStorageLabel);
|
||||
this.authentications.basicAuth.username = null;
|
||||
this.authentications.basicAuth.password = null;
|
||||
this.config.ticketEcm = null;
|
||||
this.ticket = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the client is logged in return true
|
||||
*
|
||||
* @returns `true` if client is logged in, otherwise `false`
|
||||
*/
|
||||
isLoggedIn(): boolean {
|
||||
return !!this.ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the Authentication
|
||||
*
|
||||
* @returns authentication object
|
||||
*/
|
||||
getAuthentication(): Authentication {
|
||||
return this.authentications;
|
||||
}
|
||||
}
|
21
lib/js-api/src/authentication/oauth2.ts
Normal file
21
lib/js-api/src/authentication/oauth2.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface Oauth2 {
|
||||
refreshToken?: string;
|
||||
accessToken?: string;
|
||||
}
|
778
lib/js-api/src/authentication/oauth2Auth.ts
Normal file
778
lib/js-api/src/authentication/oauth2Auth.ts
Normal file
@@ -0,0 +1,778 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import ee from 'event-emitter';
|
||||
import { AlfrescoApiClient } from '../alfrescoApiClient';
|
||||
import { AlfrescoApiConfig } from '../alfrescoApiConfig';
|
||||
import { Authentication } from './authentication';
|
||||
import { AuthenticationApi } from '../api/auth-rest-api';
|
||||
import { AlfrescoApi } from '../alfrescoApi';
|
||||
import { Storage } from '../storage';
|
||||
import { HttpClient } from '../api-clients/http-client.interface';
|
||||
import { PathMatcher } from '../utils/path-matcher';
|
||||
|
||||
declare const Buffer: any;
|
||||
|
||||
declare let window: Window;
|
||||
|
||||
interface Userinfo {
|
||||
name: string;
|
||||
given_name?: string;
|
||||
family_name?: string;
|
||||
preferred_username?: string;
|
||||
email?: string;
|
||||
picture?: string;
|
||||
}
|
||||
|
||||
export class Oauth2Auth extends AlfrescoApiClient {
|
||||
static readonly DEFAULT_AUTHORIZATION_URL = '/protocol/openid-connect/auth';
|
||||
static readonly DEFAULT_TOKEN_URL = '/protocol/openid-connect/token';
|
||||
static readonly DEFAULT_USER_INFO_ENDPOINT = '/protocol/openid-connect/userinfo';
|
||||
static readonly DEFAULT_LOGOUT_URL = '/protocol/openid-connect/logout';
|
||||
|
||||
private refreshTokenIntervalPolling: any;
|
||||
private refreshTokenTimeoutIframe: any;
|
||||
private checkAccessToken = true;
|
||||
|
||||
hashFragmentParams: any;
|
||||
token: string;
|
||||
discovery: {
|
||||
loginUrl?: string;
|
||||
logoutUrl?: string;
|
||||
tokenEndpoint?: string;
|
||||
userinfoEndpoint?: string;
|
||||
} = {
|
||||
loginUrl: undefined,
|
||||
logoutUrl: undefined,
|
||||
tokenEndpoint: undefined,
|
||||
userinfoEndpoint: undefined
|
||||
};
|
||||
|
||||
authentications: Authentication = {
|
||||
oauth2: { accessToken: '' },
|
||||
type: 'oauth2',
|
||||
basicAuth: {}
|
||||
};
|
||||
|
||||
iFrameHashListener: any;
|
||||
pathMatcher = new PathMatcher();
|
||||
|
||||
constructor(config: AlfrescoApiConfig, alfrescoApi: AlfrescoApi, httpClient?: HttpClient) {
|
||||
super(undefined, httpClient);
|
||||
this.storage = Storage.getInstance();
|
||||
|
||||
this.className = 'Oauth2Auth';
|
||||
|
||||
if (config) {
|
||||
this.setConfig(config, alfrescoApi);
|
||||
}
|
||||
}
|
||||
|
||||
setConfig(config: AlfrescoApiConfig, alfrescoApi: AlfrescoApi) {
|
||||
this.config = config;
|
||||
this.storage.setDomainPrefix(config.domainPrefix);
|
||||
|
||||
if (this.config.oauth2) {
|
||||
if (this.config.oauth2.host === undefined || this.config.oauth2.host === null) {
|
||||
throw new Error('Missing the required oauth2 host parameter');
|
||||
}
|
||||
|
||||
if (this.config.oauth2.clientId === undefined || this.config.oauth2.clientId === null) {
|
||||
throw new Error('Missing the required oauth2 clientId parameter');
|
||||
}
|
||||
|
||||
if (this.config.oauth2.scope === undefined || this.config.oauth2.scope === null) {
|
||||
throw new Error('Missing the required oauth2 scope parameter');
|
||||
}
|
||||
|
||||
if (this.config.oauth2.secret === undefined || this.config.oauth2.secret === null) {
|
||||
this.config.oauth2.secret = '';
|
||||
}
|
||||
|
||||
if ((this.config.oauth2.redirectUri === undefined || this.config.oauth2.redirectUri === null) && this.config.oauth2.implicitFlow) {
|
||||
throw new Error('Missing redirectUri required parameter');
|
||||
}
|
||||
|
||||
if (!this.config.oauth2.refreshTokenTimeout) {
|
||||
this.config.oauth2.refreshTokenTimeout = 300000;
|
||||
}
|
||||
|
||||
if (!this.config.oauth2.redirectSilentIframeUri) {
|
||||
let context = '';
|
||||
if (typeof window !== 'undefined') {
|
||||
context = window.location.origin;
|
||||
}
|
||||
this.config.oauth2.redirectSilentIframeUri = context + '/assets/silent-refresh.html';
|
||||
}
|
||||
|
||||
this.basePath = this.config.oauth2.host; //Auth Call
|
||||
|
||||
this.host = this.config.oauth2.host;
|
||||
|
||||
this.discoveryUrls();
|
||||
|
||||
if (this.hasContentProvider()) {
|
||||
this.exchangeTicketListener(alfrescoApi);
|
||||
}
|
||||
|
||||
this.initOauth();
|
||||
}
|
||||
}
|
||||
|
||||
initOauth() {
|
||||
if (!this.config.oauth2.implicitFlow && this.isValidAccessToken()) {
|
||||
const accessToken = this.storage.getItem('access_token');
|
||||
this.setToken(accessToken, null);
|
||||
}
|
||||
|
||||
if (this.config.oauth2.implicitFlow) {
|
||||
this.checkFragment('nonce');
|
||||
}
|
||||
}
|
||||
|
||||
discoveryUrls() {
|
||||
this.discovery.loginUrl = this.config.oauth2.authorizationUrl || this.host + Oauth2Auth.DEFAULT_AUTHORIZATION_URL;
|
||||
this.discovery.logoutUrl = this.config.oauth2.logoutUrl || this.host + Oauth2Auth.DEFAULT_LOGOUT_URL;
|
||||
this.discovery.tokenEndpoint = this.config.oauth2.tokenUrl || this.host + Oauth2Auth.DEFAULT_TOKEN_URL;
|
||||
this.discovery.userinfoEndpoint = this.config.oauth2.userinfoEndpoint || this.host + Oauth2Auth.DEFAULT_USER_INFO_ENDPOINT;
|
||||
}
|
||||
|
||||
getProfile(): Promise<Userinfo> {
|
||||
const postBody = {};
|
||||
const pathParams = {};
|
||||
const queryParams = {};
|
||||
|
||||
const headerParams = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
};
|
||||
|
||||
const formParams = {};
|
||||
|
||||
const contentTypes = ['application/x-www-form-urlencoded'];
|
||||
const accepts = ['application/json'];
|
||||
|
||||
return this.callCustomApi(
|
||||
this.discovery.userinfoEndpoint,
|
||||
'GET',
|
||||
pathParams,
|
||||
queryParams,
|
||||
headerParams,
|
||||
formParams,
|
||||
postBody,
|
||||
contentTypes,
|
||||
accepts
|
||||
);
|
||||
}
|
||||
|
||||
hasContentProvider(): boolean {
|
||||
return this.config.provider === 'ECM' || this.config.provider === 'ALL';
|
||||
}
|
||||
|
||||
checkFragment(nonceKey?: string, externalHash?: any): any {
|
||||
// jshint ignore:line
|
||||
this.hashFragmentParams = this.getHashFragmentParams(externalHash);
|
||||
|
||||
if (this.hashFragmentParams && this.hashFragmentParams.error === undefined) {
|
||||
this.useFragmentTimeLogin(nonceKey);
|
||||
} else {
|
||||
this.refreshBrowserLogin();
|
||||
}
|
||||
}
|
||||
|
||||
private refreshBrowserLogin() {
|
||||
if (this.config.oauth2.silentLogin && !this.isPublicUrl()) {
|
||||
this.implicitLogin();
|
||||
}
|
||||
|
||||
if (this.isValidToken() && this.isValidAccessToken()) {
|
||||
const accessToken = this.storage.getItem('access_token');
|
||||
this.setToken(accessToken, null);
|
||||
this.silentRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
private useFragmentTimeLogin(nonceKey: string) {
|
||||
const accessToken = this.hashFragmentParams.access_token;
|
||||
const idToken = this.hashFragmentParams.id_token;
|
||||
const sessionState = this.hashFragmentParams.session_state;
|
||||
const expiresIn = this.hashFragmentParams.expires_in;
|
||||
|
||||
if (!sessionState) {
|
||||
throw new Error('session state not present');
|
||||
}
|
||||
|
||||
try {
|
||||
const jwt = this.processJWTToken(idToken, nonceKey);
|
||||
if (jwt) {
|
||||
this.storeIdToken(idToken, jwt.payload.exp);
|
||||
this.storeAccessToken(accessToken, expiresIn);
|
||||
this.authentications.basicAuth.username = jwt.payload.preferred_username;
|
||||
this.saveUsername(jwt.payload.preferred_username);
|
||||
this.silentRefresh();
|
||||
return accessToken;
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error('Validation JWT error' + error);
|
||||
}
|
||||
}
|
||||
|
||||
isPublicUrl(): boolean {
|
||||
const publicUrls = this.config.oauth2.publicUrls || [];
|
||||
|
||||
if (Array.isArray(publicUrls)) {
|
||||
return publicUrls.length > 0 && publicUrls.some((urlPattern: string) => this.pathMatcher.match(window.location.href, urlPattern));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
padBase64(base64data: any) {
|
||||
while (base64data.length % 4 !== 0) {
|
||||
base64data += '=';
|
||||
}
|
||||
return base64data;
|
||||
}
|
||||
|
||||
processJWTToken(jwt: any, nonceKey: string): any {
|
||||
if (jwt) {
|
||||
const jwtArray = jwt.split('.');
|
||||
const headerBase64 = this.padBase64(jwtArray[0]);
|
||||
const headerJson = this.b64DecodeUnicode(headerBase64);
|
||||
const header = JSON.parse(headerJson);
|
||||
|
||||
const payloadBase64 = this.padBase64(jwtArray[1]);
|
||||
const payloadJson = this.b64DecodeUnicode(payloadBase64);
|
||||
const payload = JSON.parse(payloadJson);
|
||||
|
||||
const savedNonce = this.storage.getItem(nonceKey);
|
||||
|
||||
if (!payload.sub) {
|
||||
throw new Error('Missing sub in JWT');
|
||||
}
|
||||
|
||||
if (payload.nonce !== savedNonce) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
idToken: jwt,
|
||||
payload,
|
||||
header
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
b64DecodeUnicode(b64string: string) {
|
||||
const base64 = b64string.replace(/-/g, '+').replace(/_/g, '/');
|
||||
return decodeURIComponent(
|
||||
atob(base64)
|
||||
.split('')
|
||||
.map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
|
||||
.join('')
|
||||
);
|
||||
}
|
||||
|
||||
storeIdToken(idToken: string, exp: number) {
|
||||
this.storage.setItem('id_token', idToken);
|
||||
this.storage.setItem('id_token_expires_at', Number(exp * 1000).toString());
|
||||
this.storage.setItem('id_token_stored_at', Date.now().toString());
|
||||
}
|
||||
|
||||
storeAccessToken(accessToken: string, expiresIn: number, refreshToken?: string) {
|
||||
this.storage.setItem('access_token', accessToken);
|
||||
|
||||
const expiresInMilliSeconds = expiresIn * 1000;
|
||||
const now = new Date();
|
||||
const expiresAt = now.getTime() + expiresInMilliSeconds;
|
||||
|
||||
this.storage.setItem('access_token_expires_in', expiresAt);
|
||||
this.storage.setItem('access_token_stored_at', Date.now().toString());
|
||||
this.setToken(accessToken, refreshToken);
|
||||
}
|
||||
|
||||
saveUsername(username: string) {
|
||||
if (this.storage.supportsStorage()) {
|
||||
this.storage.setItem('USERNAME', username);
|
||||
}
|
||||
}
|
||||
|
||||
implicitLogin() {
|
||||
if (!this.isValidToken() || !this.isValidAccessToken()) {
|
||||
this.redirectLogin();
|
||||
}
|
||||
}
|
||||
|
||||
isValidToken(): boolean {
|
||||
let validToken = false;
|
||||
if (this.getIdToken()) {
|
||||
const expiresAt = this.storage.getItem('id_token_expires_at');
|
||||
const now = new Date();
|
||||
if (expiresAt && parseInt(expiresAt, 10) >= now.getTime()) {
|
||||
validToken = true;
|
||||
}
|
||||
}
|
||||
|
||||
return validToken;
|
||||
}
|
||||
|
||||
isValidAccessToken(): boolean {
|
||||
let validAccessToken = false;
|
||||
|
||||
if (this.getAccessToken()) {
|
||||
const expiresAt = this.storage.getItem('access_token_expires_in');
|
||||
const now = new Date();
|
||||
if (expiresAt && parseInt(expiresAt, 10) >= now.getTime()) {
|
||||
validAccessToken = true;
|
||||
}
|
||||
}
|
||||
|
||||
return validAccessToken;
|
||||
}
|
||||
|
||||
getIdToken(): string {
|
||||
return this.storage.getItem('id_token');
|
||||
}
|
||||
|
||||
getAccessToken(): string {
|
||||
return this.storage.getItem('access_token');
|
||||
}
|
||||
|
||||
redirectLogin(): void {
|
||||
if (this.config.oauth2.implicitFlow && typeof window !== 'undefined') {
|
||||
const href = this.composeImplicitLoginUrl();
|
||||
window.location.href = href;
|
||||
this.emit('implicit_redirect', href);
|
||||
}
|
||||
}
|
||||
|
||||
isRedirectionUrl() {
|
||||
return window.location.hash && window.location.hash.split('&')[0].indexOf('session_state') === -1;
|
||||
}
|
||||
|
||||
genNonce(): string {
|
||||
let text = '';
|
||||
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
||||
for (let i = 0; i < 40; i++) {
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
composeImplicitLoginUrl(): string {
|
||||
const nonce = this.genNonce();
|
||||
|
||||
this.storage.setItem('nonce', nonce);
|
||||
|
||||
const afterLoginUriSegment = this.isRedirectionUrl() ? window.location.hash : '';
|
||||
if (afterLoginUriSegment && afterLoginUriSegment !== '/') {
|
||||
this.storage.setItem('loginFragment', afterLoginUriSegment.replace('#', '').trim());
|
||||
}
|
||||
|
||||
const separation = this.discovery.loginUrl.indexOf('?') > -1 ? '&' : '?';
|
||||
|
||||
return (
|
||||
this.discovery.loginUrl +
|
||||
separation +
|
||||
'client_id=' +
|
||||
encodeURIComponent(this.config.oauth2.clientId) +
|
||||
'&redirect_uri=' +
|
||||
encodeURIComponent(this.config.oauth2.redirectUri) +
|
||||
'&scope=' +
|
||||
encodeURIComponent(this.config.oauth2.scope) +
|
||||
'&response_type=' +
|
||||
encodeURIComponent('id_token token') +
|
||||
'&nonce=' +
|
||||
encodeURIComponent(nonce)
|
||||
);
|
||||
}
|
||||
|
||||
composeIframeLoginUrl(): string {
|
||||
const nonce = this.genNonce();
|
||||
|
||||
this.storage.setItem('refresh_nonce', nonce);
|
||||
|
||||
const separation = this.discovery.loginUrl.indexOf('?') > -1 ? '&' : '?';
|
||||
|
||||
return (
|
||||
this.discovery.loginUrl +
|
||||
separation +
|
||||
'client_id=' +
|
||||
encodeURIComponent(this.config.oauth2.clientId) +
|
||||
'&redirect_uri=' +
|
||||
encodeURIComponent(this.config.oauth2.redirectSilentIframeUri) +
|
||||
'&scope=' +
|
||||
encodeURIComponent(this.config.oauth2.scope) +
|
||||
'&response_type=' +
|
||||
encodeURIComponent('id_token token') +
|
||||
'&nonce=' +
|
||||
encodeURIComponent(nonce) +
|
||||
'&prompt=none'
|
||||
);
|
||||
}
|
||||
|
||||
hasHashCharacter(hash: string): boolean {
|
||||
return hash.indexOf('#') === 0;
|
||||
}
|
||||
|
||||
startWithHashRoute(hash: string) {
|
||||
return hash.startsWith('#/');
|
||||
}
|
||||
|
||||
getHashFragmentParams(externalHash: string): string {
|
||||
let hashFragmentParams = null;
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
let hash: string;
|
||||
|
||||
if (!externalHash) {
|
||||
hash = decodeURIComponent(window.location.hash);
|
||||
if (!this.startWithHashRoute(hash)) {
|
||||
window.location.hash = '';
|
||||
}
|
||||
} else {
|
||||
hash = decodeURIComponent(externalHash);
|
||||
this.removeHashFromSilentIframe();
|
||||
this.destroyIframe();
|
||||
}
|
||||
|
||||
if (this.hasHashCharacter(hash) && !this.startWithHashRoute(hash)) {
|
||||
const questionMarkPosition = hash.indexOf('?');
|
||||
|
||||
if (questionMarkPosition > -1) {
|
||||
hash = hash.substring(questionMarkPosition + 1);
|
||||
} else {
|
||||
hash = hash.substring(1);
|
||||
}
|
||||
hashFragmentParams = this.parseQueryString(hash);
|
||||
}
|
||||
}
|
||||
return hashFragmentParams;
|
||||
}
|
||||
|
||||
parseQueryString(queryString: string): any {
|
||||
const data: { [key: string]: any } = {};
|
||||
let pairs: string[];
|
||||
let pair: string;
|
||||
let separatorIndex: number;
|
||||
let escapedKey: string;
|
||||
let escapedValue: string;
|
||||
let key: string;
|
||||
let value: string;
|
||||
|
||||
if (queryString !== null) {
|
||||
pairs = queryString.split('&');
|
||||
|
||||
for (const item of pairs) {
|
||||
pair = item;
|
||||
separatorIndex = pair.indexOf('=');
|
||||
|
||||
if (separatorIndex === -1) {
|
||||
escapedKey = pair;
|
||||
escapedValue = null;
|
||||
} else {
|
||||
escapedKey = pair.substring(0, separatorIndex);
|
||||
escapedValue = pair.substring(separatorIndex + 1);
|
||||
}
|
||||
|
||||
key = decodeURIComponent(escapedKey);
|
||||
value = decodeURIComponent(escapedValue);
|
||||
|
||||
if (key.startsWith('/')) {
|
||||
key = key.substring(1);
|
||||
}
|
||||
|
||||
data[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
silentRefresh(): void {
|
||||
if (typeof document === 'undefined') {
|
||||
this.pollingRefreshToken();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.checkAccessToken) {
|
||||
this.destroyIframe();
|
||||
this.createIframe();
|
||||
this.checkAccessToken = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.refreshTokenTimeoutIframe = setTimeout(() => {
|
||||
this.destroyIframe();
|
||||
this.createIframe();
|
||||
}, this.config.oauth2.refreshTokenTimeout);
|
||||
}
|
||||
|
||||
removeHashFromSilentIframe() {
|
||||
const iframe = document.getElementById('silent_refresh_token_iframe') as HTMLIFrameElement;
|
||||
if (iframe?.contentWindow.location.hash) {
|
||||
iframe.contentWindow.location.hash = '';
|
||||
}
|
||||
}
|
||||
|
||||
createIframe() {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.id = 'silent_refresh_token_iframe';
|
||||
const loginUrl = this.composeIframeLoginUrl();
|
||||
iframe.setAttribute('src', loginUrl);
|
||||
iframe.style.display = 'none';
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
this.iFrameHashListener = () => {
|
||||
const silentRefreshTokenIframe: any = document.getElementById('silent_refresh_token_iframe');
|
||||
const hash = silentRefreshTokenIframe.contentWindow.location.hash;
|
||||
try {
|
||||
this.checkFragment('refresh_nonce', hash);
|
||||
} catch {
|
||||
this.logOut();
|
||||
}
|
||||
};
|
||||
|
||||
iframe.addEventListener('load', this.iFrameHashListener);
|
||||
}
|
||||
|
||||
destroyIframe() {
|
||||
const iframe = document.getElementById('silent_refresh_token_iframe');
|
||||
|
||||
if (iframe) {
|
||||
iframe.removeEventListener('load', this.iFrameHashListener);
|
||||
document.body.removeChild(iframe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* login Alfresco API
|
||||
*
|
||||
* @returns A promise that returns {new authentication token} if resolved and {error} if rejected.
|
||||
*/
|
||||
login(username: string, password: string): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.grantPasswordLogin(username, password, resolve, reject);
|
||||
});
|
||||
}
|
||||
|
||||
grantPasswordLogin(username: string, password: string, resolve: any, reject: any) {
|
||||
this.invalidateSession();
|
||||
|
||||
const headerParams = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
};
|
||||
|
||||
const formParams = {
|
||||
username,
|
||||
password,
|
||||
grant_type: 'password',
|
||||
client_id: this.config.oauth2.clientId,
|
||||
client_secret: this.config.oauth2.secret
|
||||
};
|
||||
|
||||
const contentTypes = ['application/x-www-form-urlencoded'];
|
||||
const accepts = ['application/json'];
|
||||
|
||||
const promise = this.callCustomApi(this.discovery.tokenEndpoint, 'POST', {}, {}, headerParams, formParams, {}, contentTypes, accepts).then(
|
||||
(data: any) => {
|
||||
this.saveUsername(username);
|
||||
this.silentRefresh();
|
||||
this.storeAccessToken(data.access_token, data.expires_in, data.refresh_token);
|
||||
|
||||
resolve(data);
|
||||
},
|
||||
(error) => {
|
||||
if ((error.error && error.error.status === 401) || error.status === 401) {
|
||||
this.emit('unauthorized');
|
||||
}
|
||||
this.emit('error');
|
||||
reject(error.error);
|
||||
}
|
||||
);
|
||||
|
||||
ee(promise); // jshint ignore:line
|
||||
}
|
||||
|
||||
pollingRefreshToken() {
|
||||
this.refreshTokenIntervalPolling = setInterval(async () => {
|
||||
try {
|
||||
await this.refreshToken();
|
||||
} catch {
|
||||
/* continue regardless of error */
|
||||
}
|
||||
}, this.config.oauth2.refreshTokenTimeout);
|
||||
|
||||
this.refreshTokenIntervalPolling.unref();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the Token
|
||||
*
|
||||
* @returns promise of void
|
||||
*/
|
||||
refreshToken(): Promise<any> {
|
||||
const auth = 'Basic ' + this.universalBtoa(this.config.oauth2.clientId + ':' + this.config.oauth2.secret);
|
||||
const headerParams = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Cache-Control': 'no-cache',
|
||||
Authorization: auth
|
||||
};
|
||||
const formParams = {
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: this.authentications.oauth2.refreshToken
|
||||
};
|
||||
|
||||
const contentTypes = ['application/x-www-form-urlencoded'];
|
||||
const accepts = ['application/json'];
|
||||
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
this.callCustomApi(this.discovery.tokenEndpoint, 'POST', {}, {}, headerParams, formParams, {}, contentTypes, accepts).then(
|
||||
(data: any) => {
|
||||
this.setToken(data.access_token, data.refresh_token);
|
||||
resolve(data);
|
||||
},
|
||||
(error) => {
|
||||
if (error.error && error.error.status === 401) {
|
||||
this.emit('unauthorized');
|
||||
}
|
||||
this.emit('error');
|
||||
reject(error.error);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
ee(promise); // jshint ignore:line
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
universalBtoa(stringToConvert: string) {
|
||||
try {
|
||||
return btoa(stringToConvert);
|
||||
} catch (err) {
|
||||
return Buffer.from(stringToConvert).toString('base64');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current Token
|
||||
*/
|
||||
setToken(token: string, refreshToken: string) {
|
||||
this.authentications.oauth2.accessToken = token;
|
||||
this.authentications.oauth2.refreshToken = refreshToken;
|
||||
this.authentications.basicAuth.password = null;
|
||||
this.token = token;
|
||||
|
||||
if (token) {
|
||||
this.emit('token_issued');
|
||||
this.emit('logged-in');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current Token
|
||||
*
|
||||
* @returns token value
|
||||
*/
|
||||
getToken(): string {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the Authentication
|
||||
*
|
||||
* @returns authentications
|
||||
*/
|
||||
getAuthentication(): Authentication {
|
||||
return this.authentications;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the Host
|
||||
*/
|
||||
changeHost(host: string) {
|
||||
this.config.hostOauth2 = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the client is logged in return true
|
||||
*
|
||||
* @returns is logged in
|
||||
*/
|
||||
isLoggedIn(): boolean {
|
||||
return !!this.authentications.oauth2.accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout
|
||||
*/
|
||||
async logOut() {
|
||||
this.checkAccessToken = true;
|
||||
|
||||
const id_token = this.getIdToken();
|
||||
|
||||
this.invalidateSession();
|
||||
this.setToken(null, null);
|
||||
|
||||
const separation = this.discovery.logoutUrl.indexOf('?') > -1 ? '&' : '?';
|
||||
const redirectLogout = this.config.oauth2.redirectUriLogout || this.config.oauth2.redirectUri;
|
||||
const logoutUrl =
|
||||
this.discovery.logoutUrl +
|
||||
separation +
|
||||
'post_logout_redirect_uri=' +
|
||||
encodeURIComponent(redirectLogout) +
|
||||
'&id_token_hint=' +
|
||||
encodeURIComponent(id_token);
|
||||
|
||||
if (id_token != null && this.config.oauth2.implicitFlow && typeof window !== 'undefined') {
|
||||
window.location.href = logoutUrl;
|
||||
}
|
||||
}
|
||||
|
||||
invalidateSession() {
|
||||
clearTimeout(this.refreshTokenTimeoutIframe);
|
||||
clearInterval(this.refreshTokenIntervalPolling);
|
||||
|
||||
this.storage.removeItem('access_token');
|
||||
this.storage.removeItem('access_token_expires_in');
|
||||
this.storage.removeItem('access_token_stored_at');
|
||||
|
||||
this.storage.removeItem('id_token');
|
||||
this.storage.removeItem('id_token');
|
||||
this.storage.removeItem('id_token_claims_obj');
|
||||
this.storage.removeItem('id_token_expires_at');
|
||||
this.storage.removeItem('id_token_stored_at');
|
||||
|
||||
this.storage.removeItem('nonce');
|
||||
}
|
||||
|
||||
exchangeTicketListener(alfrescoApi: AlfrescoApi) {
|
||||
this.on('token_issued', async () => {
|
||||
const authContentApi: AuthenticationApi = new AuthenticationApi(alfrescoApi);
|
||||
// Legacy stuff, needs deprecation, can not be more specific here because of circular dependency
|
||||
(authContentApi.apiClient as unknown as any).authentications = this.authentications;
|
||||
try {
|
||||
const ticketEntry = await authContentApi.getTicket();
|
||||
this.config.ticketEcm = ticketEntry.entry.id;
|
||||
this.emit('ticket_exchanged');
|
||||
} catch (e) {
|
||||
// continue regardless of error
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
34
lib/js-api/src/authentication/oauth2Config.ts
Normal file
34
lib/js-api/src/authentication/oauth2Config.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface Oauth2Config {
|
||||
clientId: string;
|
||||
secret?: string;
|
||||
host: string;
|
||||
authorizationUrl?: string;
|
||||
tokenUrl?: string;
|
||||
userinfoEndpoint?: string;
|
||||
logoutUrl?: string;
|
||||
scope: string;
|
||||
implicitFlow?: boolean;
|
||||
redirectUri: string;
|
||||
refreshTokenTimeout?: number;
|
||||
silentLogin?: boolean;
|
||||
redirectUriLogout?: string;
|
||||
redirectSilentIframeUri?: string;
|
||||
publicUrls?: string[];
|
||||
}
|
211
lib/js-api/src/authentication/processAuth.ts
Normal file
211
lib/js-api/src/authentication/processAuth.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import ee from 'event-emitter';
|
||||
import { AlfrescoApiClient, AlfrescoApiClientPromise } from '../alfrescoApiClient';
|
||||
import { AlfrescoApiConfig } from '../alfrescoApiConfig';
|
||||
import { Authentication } from './authentication';
|
||||
import { Storage } from '../storage';
|
||||
import { HttpClient } from '../api-clients/http-client.interface';
|
||||
import { isBrowser } from '../utils';
|
||||
|
||||
export class ProcessAuth extends AlfrescoApiClient {
|
||||
ticket: string;
|
||||
|
||||
authentications: Authentication = {
|
||||
basicAuth: { ticket: '' },
|
||||
type: 'activiti'
|
||||
};
|
||||
|
||||
constructor(config: AlfrescoApiConfig, httpClient?: HttpClient) {
|
||||
super(undefined, httpClient);
|
||||
this.storage = Storage.getInstance();
|
||||
this.storage.setDomainPrefix(config.domainPrefix);
|
||||
|
||||
this.className = 'ProcessAuth';
|
||||
|
||||
if (!isBrowser()) {
|
||||
this.defaultHeaders = {
|
||||
'user-agent': 'alfresco-js-api'
|
||||
};
|
||||
}
|
||||
|
||||
this.setConfig(config);
|
||||
}
|
||||
|
||||
setConfig(config: AlfrescoApiConfig) {
|
||||
this.config = config;
|
||||
this.ticket = undefined;
|
||||
|
||||
this.basePath = config.hostBpm + '/' + this.config.contextRootBpm; //Activiti Call
|
||||
|
||||
if (this.config.ticketBpm) {
|
||||
this.setTicket(config.ticketBpm);
|
||||
} else if (this.storage.getItem('ticket-BPM')) {
|
||||
this.setTicket(this.storage.getItem('ticket-BPM'));
|
||||
}
|
||||
}
|
||||
|
||||
changeHost() {
|
||||
this.basePath = this.config.hostBpm + '/' + this.config.contextRootBpm; //Activiti Call
|
||||
this.ticket = undefined;
|
||||
}
|
||||
|
||||
changeCsrfConfig(disableCsrf: boolean) {
|
||||
this.config.disableCsrf = disableCsrf;
|
||||
}
|
||||
|
||||
saveUsername(username: string) {
|
||||
if (this.storage.supportsStorage()) {
|
||||
this.storage.setItem('APS_USERNAME', username);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* login Activiti API
|
||||
*
|
||||
* @param username Username to login
|
||||
* @param password Password to login
|
||||
* @returns A promise that returns {new authentication ticket} if resolved and {error} if rejected.
|
||||
*/
|
||||
login(username: string, password: string): AlfrescoApiClientPromise<string> {
|
||||
this.authentications.basicAuth.username = username;
|
||||
this.authentications.basicAuth.password = password;
|
||||
|
||||
const headerParams = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Cache-Control': 'no-cache'
|
||||
};
|
||||
const formParams = {
|
||||
j_username: this.authentications.basicAuth.username,
|
||||
j_password: this.authentications.basicAuth.password,
|
||||
_spring_security_remember_me: true,
|
||||
submit: 'Login'
|
||||
};
|
||||
|
||||
const contentTypes = ['application/x-www-form-urlencoded'];
|
||||
const accepts = ['application/json'];
|
||||
|
||||
const promise: any = new Promise<string>((resolve, reject) => {
|
||||
this.callApi('/app/authentication', 'POST', {}, {}, headerParams, formParams, {}, contentTypes, accepts).then(
|
||||
() => {
|
||||
this.saveUsername(username);
|
||||
const ticket = this.basicAuth(this.authentications.basicAuth.username, this.authentications.basicAuth.password);
|
||||
this.setTicket(ticket);
|
||||
promise.emit('success');
|
||||
this.emit('logged-in');
|
||||
resolve(ticket);
|
||||
},
|
||||
(error) => {
|
||||
this.saveUsername('');
|
||||
if (error.status === 401) {
|
||||
promise.emit('unauthorized');
|
||||
} else if (error.status === 403) {
|
||||
promise.emit('forbidden');
|
||||
} else {
|
||||
promise.emit('error');
|
||||
}
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
ee(promise); // jshint ignore:line
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* logout Alfresco API
|
||||
*
|
||||
* @returns A promise that returns {new authentication ticket} if resolved and {error} if rejected.
|
||||
*/
|
||||
logout(): AlfrescoApiClientPromise<void> {
|
||||
this.saveUsername('');
|
||||
|
||||
const contentTypes = ['application/json'];
|
||||
const accepts = ['application/json'];
|
||||
|
||||
const promise: any = new Promise<void>((resolve, reject) => {
|
||||
this.callApi('/app/logout', 'GET', {}, {}, {}, {}, {}, contentTypes, accepts).then(
|
||||
() => {
|
||||
this.invalidateSession();
|
||||
promise.emit('logout');
|
||||
resolve();
|
||||
},
|
||||
(error) => {
|
||||
if (error.status === 401) {
|
||||
promise.emit('unauthorized');
|
||||
}
|
||||
promise.emit('error');
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
ee(promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current Ticket
|
||||
*
|
||||
* @param ticket Ticket value
|
||||
*/
|
||||
setTicket(ticket: string) {
|
||||
this.authentications.basicAuth.ticket = ticket;
|
||||
this.authentications.basicAuth.password = null;
|
||||
this.config.ticketBpm = ticket;
|
||||
this.storage.setItem('ticket-BPM', ticket);
|
||||
this.ticket = ticket;
|
||||
}
|
||||
|
||||
invalidateSession() {
|
||||
this.storage.removeItem('ticket-BPM');
|
||||
this.authentications.basicAuth.ticket = null;
|
||||
this.authentications.basicAuth.password = null;
|
||||
this.authentications.basicAuth.username = null;
|
||||
this.config.ticketBpm = null;
|
||||
this.ticket = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current Ticket
|
||||
*
|
||||
* @returns ticket
|
||||
*/
|
||||
getTicket(): string {
|
||||
return this.ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the client is logged in return true
|
||||
*
|
||||
* @returns `true` if logged in, otherwise `false`
|
||||
*/
|
||||
isLoggedIn(): boolean {
|
||||
return !!this.ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the Authentication
|
||||
*
|
||||
* @returns authentication object
|
||||
*/
|
||||
getAuthentication(): Authentication {
|
||||
return this.authentications;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user