Skip to content

Commit

Permalink
Cleaned up authentication logic. Fixed issue with read-only props in …
Browse files Browse the repository at this point in the history
…schema. Fixes Map widget issue. (#1115)
  • Loading branch information
azaslonov authored Jan 12, 2021
1 parent 87791e0 commit 57ef709
Show file tree
Hide file tree
Showing 12 changed files with 64 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,13 @@ export class ChangePassword {
}

const user = await this.usersService.getCurrentUser();

let userId = await this.usersService.authenticate(user.email, this.password());
const credentials = `Basic ${btoa(`${user.email}:${this.password()}`)}`;
let userId = await this.usersService.authenticate(credentials);

if (!userId) {
const validationReport: ValidationReport = {
source: "changepassword",
errors: ["Password is not valid"]
errors: ["Incorrect user name or password"]
};
this.eventManager.dispatchEvent("onValidationErrors", validationReport);
return;
Expand Down
1 change: 1 addition & 0 deletions src/components/users/signin/ko/runtime/signin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export class Signin {
if (userId) {
const clientReturnUrl = sessionStorage.getItem("returnUrl");
const returnUrl = this.routeHelper.getQueryParameter("returnUrl") || clientReturnUrl;

if (returnUrl) {
this.router.navigateTo(returnUrl);
return;
Expand Down
2 changes: 2 additions & 0 deletions src/contracts/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export interface SchemaObjectContract extends ReferenceObjectContract {
*/
required?: string[];

readOnly?: boolean;

properties?: Bag<SchemaObjectContract>;

items?: SchemaObjectContract;
Expand Down
2 changes: 1 addition & 1 deletion src/models/knownHttpHeaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ export const KnownHttpHeaders = {
OcpApimTraceLocation: "Ocp-Apim-Trace-Location",
OcpApimSasToken: "Ocp-Apim-Sas-Token",
SoapAction: "SOAPAction",
}
};
6 changes: 5 additions & 1 deletion src/models/typeDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ export class TypeDefinitionObjectProperty extends TypeDefinitionProperty {
try {
const propertySchemaObject = contract.properties[propertyName];

if (propertySchemaObject.readOnly) {
return;
}

if (!propertySchemaObject) {
return;
}
Expand Down Expand Up @@ -265,7 +269,7 @@ export class TypeDefinitionObjectProperty extends TypeDefinitionProperty {
arrayProperty.type = new TypeDefinitionPropertyTypeArrayOfReference(getTypeNameFromRef(propertySchemaObject.items.$ref));
props.push(arrayProperty);
}
else if (propertySchemaObject.items.properties) {
else if (propertySchemaObject.items.properties) {
const objectProperty = new TypeDefinitionObjectProperty(propertyName, propertySchemaObject.items, isRequired, true);
const flattenObjects = this.flattenNestedObjects(objectProperty, propertyName + "[]");
props.push(...flattenObjects);
Expand Down
25 changes: 5 additions & 20 deletions src/services/aadService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,10 @@ export class AadService {
* @param provider {string} Provider type, "Aad" or "AadB2C".
*/
private async exchangeIdToken(idToken: string, provider: string): Promise<void> {
let managementApiUrl = await this.settingsProvider.getSetting<string>(Constants.SettingNames.managementApiUrl);
managementApiUrl = Utils.ensureUrlArmified(managementApiUrl);

const request = {
url: `${managementApiUrl}/identity?api-version=${Constants.managementApiVersion}`,
method: "GET",
headers: [
{ name: "Authorization", value: `${provider} id_token="${idToken}"` },
MapiClient.getPortalHeader()
]
};

const response = await this.httpClient.send(request);
const sasTokenHeader = response.headers.find(x => x.name.toLowerCase() === "ocp-apim-sas-token");
const returnUrl = this.routeHelper.getQueryParameter("returnUrl") || Constants.pageUrlHome;
const credentials = `${provider} id_token="${idToken}"`;
const userId = await this.usersService.authenticate(credentials);

if (sasTokenHeader) {
const accessToken = AccessToken.parse(sasTokenHeader.value);
await this.authenticator.setAccessToken(accessToken);
}
else { // User not registered with APIM.
if (!userId) { // User not registered with APIM.
const jwtToken = Utils.parseJwt(idToken);
const firstName = jwtToken.given_name;
const lastName = jwtToken.family_name;
Expand All @@ -65,6 +48,8 @@ export class AadService {
}
}

const returnUrl = this.routeHelper.getQueryParameter("returnUrl") || Constants.pageUrlHome;

this.router.getCurrentUrl() === returnUrl
? location.reload()
: await this.router.navigateTo(returnUrl);
Expand Down
21 changes: 5 additions & 16 deletions src/services/mapiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,16 @@ export class MapiClient {
protected async makeRequest<T>(httpRequest: HttpRequest): Promise<T> {
const authHeader = httpRequest.headers.find(header => header.name === KnownHttpHeaders.Authorization);

if (!authHeader || !authHeader.value) {
const authToken = await this.authenticator.getAccessToken();
if (!authHeader?.value) {
const accessToken = await this.authenticator.getAccessToken();

if (authToken) {
httpRequest.headers.push({ name: KnownHttpHeaders.Authorization, value: `${authToken}` });
if (accessToken) {
httpRequest.headers.push({ name: KnownHttpHeaders.Authorization, value: `${accessToken}` });
}
}

const portalHeader = httpRequest.headers.find(header => header.name === Constants.portalHeaderName);

if (!portalHeader) {
httpRequest.headers.push(MapiClient.getPortalHeader());
}
Expand All @@ -140,18 +141,6 @@ export class MapiClient {
throw new Error(`Unable to complete request. Error: ${error.message}`);
}

const accessTokenHeader = response.headers.find(x => x.name.toLowerCase() === KnownHttpHeaders.OcpApimSasToken.toLowerCase());

if (accessTokenHeader) {
try {
const accessToken = AccessToken.parse(accessTokenHeader.value);
await this.authenticator.setAccessToken(accessToken);
}
catch (error) {
this.logger.trackError(error, { message: "Unable to refresh access token." });
}
}

return await this.handleResponse<T>(response, httpRequest.url);
}

Expand Down
51 changes: 36 additions & 15 deletions src/services/usersService.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { KnownHttpHeaders } from "./../models/knownHttpHeaders";
import { AccessToken } from "./../authentication/accessToken";
import * as Constants from "./../constants";
import { Router } from "@paperbits/common/routing";
Expand Down Expand Up @@ -31,26 +32,46 @@ export class UsersService {
* @param password {string} Password.
*/
public async signIn(username: string, password: string): Promise<string> {
const userId = await this.authenticate(username, password);
const credentials = `Basic ${btoa(`${username}:${password}`)}`;
const userId = await this.authenticate(credentials);

if (userId) {
return userId;
}
else {
this.authenticator.clearAccessToken();
return undefined;
}
}

public async authenticate(username: string, password: string): Promise<string> {
const credentials = `Basic ${btoa(`${username}:${password}`)}`;
this.authenticator.clearAccessToken();
return undefined;
}

/**
* Authenticates user with specified credentilas and returns user identifier.
* @param credentials {string} User credentials passed in "Authorization" header.
* @returns {string} User identifier.
*/
public async authenticate(credentials: string): Promise<string> {
try {
const identity = await this.mapiClient.get<Identity>("/identity", [{ name: "Authorization", value: credentials }, MapiClient.getPortalHeader("authenticate")]);
let managementApiUrl = await this.settingsProvider.getSetting<string>(Constants.SettingNames.managementApiUrl);
managementApiUrl = Utils.ensureUrlArmified(managementApiUrl);

const request = {
url: `${managementApiUrl}/identity?api-version=${Constants.managementApiVersion}`,
method: "GET",
headers: [
{ name: "Authorization", value: credentials },
MapiClient.getPortalHeader()
]
};

if (identity && identity.id) {
return identity.id;
const response = await this.httpClient.send<Identity>(request);
const sasTokenHeader = response.headers.find(x => x.name.toLowerCase() === KnownHttpHeaders.OcpApimSasToken.toLowerCase());

if (sasTokenHeader) {
const accessToken = AccessToken.parse(sasTokenHeader.value);
await this.authenticator.setAccessToken(accessToken);
}

const identity = response.toObject();
return identity?.id;
}
catch (error) {
return undefined;
Expand Down Expand Up @@ -246,7 +267,7 @@ export class UsersService {

const headers = [
{ name: "Authorization", value: authToken },
{ name: "If-Match", value: "*" },
{ name: "If-Match", value: "*" },
MapiClient.getPortalHeader("changePassword")
];

Expand All @@ -255,7 +276,7 @@ export class UsersService {
password: newPassword
}
};

await this.mapiClient.patch(`${userId}?appType=${Constants.AppType}`, headers, payload);
}

Expand Down Expand Up @@ -289,9 +310,9 @@ export class UsersService {
throw MapiError.fromResponse(response);
}

const sasTokenHeader = response.headers.find(x => x.name.toLowerCase() === "ocp-apim-sas-token");
const sasTokenHeader = response.headers.find(x => x.name.toLowerCase() === KnownHttpHeaders.OcpApimSasToken.toLowerCase());

if (!sasTokenHeader) { // User not registered with APIM.
if (!sasTokenHeader) { // User still not registered with APIM.
throw new Error("Unable to authenticate.");
return;
}
Expand Down
2 changes: 2 additions & 0 deletions src/startup.runtime.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { InversifyInjector } from "@paperbits/common/injection";
import { CoreRuntimeModule } from "@paperbits/core/core.runtime.module";
import { ApimRuntimeModule } from "./apim.runtime.module";


const injector = new InversifyInjector();
injector.bindModule(new CoreRuntimeModule());
injector.bindModule(new ApimRuntimeModule());

document.addEventListener("DOMContentLoaded", () => {
Expand Down
1 change: 1 addition & 0 deletions src/themes/designer/styles/lists.scss
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
line-height: 1.5em;
margin-bottom: 15px;
flex-basis: auto;
vertical-align: top;

a {
display: inline-block;
Expand Down
2 changes: 0 additions & 2 deletions src/themes/website/styles/layouts.scss
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,6 @@ main {

* {
max-width: 100%;
max-height: 100%;
}
}

Expand All @@ -418,7 +417,6 @@ main {

* {
max-width: 100%;
max-height: 100%;
}
}

Expand Down
18 changes: 3 additions & 15 deletions src/themes/website/styles/widgets/map.scss
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
.paperbits-googlemaps {
width: 100%;
min-height: 200px;
border: 0;
position: relative;


& > div {
pointer-events: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
map,
map-runtime {
display: block;
}

0 comments on commit 57ef709

Please sign in to comment.