From 9e8c9c1633cdf2939a062129f6a64c6aa38c892c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20L=C3=BCthi?= Date: Thu, 14 Dec 2023 11:50:06 +0100 Subject: [PATCH 01/31] Add oidc-server mock --- config/oidc-mock-clients.json | 26 +++++++++++++++++++++++ config/oidc-mock-users.json | 39 +++++++++++++++++++++++++++++++++++ docker-compose.yml | 21 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 config/oidc-mock-clients.json create mode 100644 config/oidc-mock-users.json diff --git a/config/oidc-mock-clients.json b/config/oidc-mock-clients.json new file mode 100644 index 000000000..845ecc99e --- /dev/null +++ b/config/oidc-mock-clients.json @@ -0,0 +1,26 @@ +[{ + "ClientId": "bdms-client", + "Description": "Client for Authorization Code flow with PKCE", + "RequireClientSecret": false, + "AlwaysIncludeUserClaimsInIdToken": true, + "AllowedGrantTypes": [ + "authorization_code" + ], + "AllowedResponseTypes": [ + "code", + "id_token" + ], + "AllowAccessTokensViaBrowser": true, + "RedirectUris": [ + "http://localhost:3000" + ], + "AllowedScopes": [ + "openid", + "profile", + "email" + ], + "AccessTokenType": "JWT", + "IdentityTokenLifetime": 3600, + "AccessTokenLifetime": 3600 +} +] diff --git a/config/oidc-mock-users.json b/config/oidc-mock-users.json new file mode 100644 index 000000000..d14b774dc --- /dev/null +++ b/config/oidc-mock-users.json @@ -0,0 +1,39 @@ +[ + { + "SubjectId":"admin", + "Username":"admin", + "Password":"swissforages", + "Claims": [ + { + "Type": "name", + "Value": "Sam Jackson", + "ValueType": "string" + }, + { + "Type": "family_name", + "Value": "Jackson", + "ValueType": "string" + }, + { + "Type": "given_name", + "Value": "Sam", + "ValueType": "string" + }, + { + "Type": "middle_name", + "Value": "L.", + "ValueType": "string" + }, + { + "Type": "email", + "Value": "sam.tailor@gmail.com", + "ValueType": "string" + }, + { + "Type": "email_verified", + "Value": "true", + "ValueType": "boolean" + } + ] + } +] diff --git a/docker-compose.yml b/docker-compose.yml index aa4f049e8..c36ebb55b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -120,3 +120,24 @@ services: ReverseProxy__Clusters__pythonApi__Destinations__legacyApi__Address: "http://api-legacy:8888/" S3__ENDPOINT: http://minio:9000 S3__SECURE: 1 + oidc-server: + image: soluto/oidc-server-mock + ports: + - "4011:80" + environment: + CLIENTS_CONFIGURATION_PATH: /tmp/config/clients-config.json + USERS_CONFIGURATION_PATH: /tmp/config/users-config.json + SERVER_OPTIONS_INLINE: | + { + "AccessTokenJwtType": "JWT", + "Discovery": { + "ShowKeySet": true + }, + "Authentication": { + "CookieSameSiteMode": "Lax", + "CheckSessionCookieSameSiteMode": "Lax" + } + } + volumes: + - ./config/oidc-mock-clients.json:/tmp/config/clients-config.json:ro + - ./config/oidc-mock-users.json:/tmp/config/users-config.json:ro From 84ed00b69270003c4967305b9c812902b7c03c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20L=C3=BCthi?= Date: Thu, 14 Dec 2023 11:52:24 +0100 Subject: [PATCH 02/31] Add oidc authentication to api --- .../BasicAuthenticationHandler.cs | 66 ------------------- ...tabaseAuthenticationClaimsTranfomration.cs | 43 ++++++++++++ src/api/BDMS.csproj | 1 + src/api/Program.cs | 17 ++--- src/api/appsettings.Development.json | 5 ++ 5 files changed, 58 insertions(+), 74 deletions(-) delete mode 100644 src/api/Authentication/BasicAuthenticationHandler.cs create mode 100644 src/api/Authentication/DatabaseAuthenticationClaimsTranfomration.cs diff --git a/src/api/Authentication/BasicAuthenticationHandler.cs b/src/api/Authentication/BasicAuthenticationHandler.cs deleted file mode 100644 index 8ead2d82f..000000000 --- a/src/api/Authentication/BasicAuthenticationHandler.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Options; -using Npgsql; -using System.Security.Claims; -using System.Text; -using System.Text.Encodings.Web; - -namespace BDMS.Authentication; - -public class BasicAuthenticationHandler : AuthenticationHandler -{ - private readonly BdmsContext dbContext; - - /// - /// Initializes a new instance of the class. - /// - /// The EF database context containing data for the BDMS application. - /// The monitor for the options instance. - /// The . - /// The . - /// If is null. - public BasicAuthenticationHandler(BdmsContext dbContext, IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder) - : base(options, logger, encoder) - { - this.dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); - } - - /// - protected override Task HandleAuthenticateAsync() - { - var authorizationHeader = Request.Headers.Authorization.ToString(); - if (authorizationHeader != null && authorizationHeader.StartsWith("basic ", StringComparison.OrdinalIgnoreCase)) - { - // Get username and password from base64 encoded authorization header - var token = authorizationHeader[6..].Trim(); - var credentialstring = Encoding.UTF8.GetString(Convert.FromBase64String(token)); - var credentials = credentialstring.Split(':', 2); - - // Get authenticated user from database - var authenticatedUser = dbContext.Users - .FromSqlRaw( - "SELECT * FROM bdms.users WHERE username = @username AND password = crypt(@password, password)", - new NpgsqlParameter("@username", credentials[0]), - new NpgsqlParameter("@password", credentials[1])) - .SingleOrDefault(); - - // Handle invalid or disabled user - if (authenticatedUser == null || authenticatedUser.IsDisabled) - { - return Task.FromResult(AuthenticateResult.Fail("No valid authentication credentials have been provided or the specified user has been disabled in the backend.")); - } - - var claimsIdentity = new ClaimsIdentity(); - claimsIdentity.AddClaim(new Claim(ClaimTypes.AuthenticationMethod, "Basic")); - claimsIdentity.AddClaim(new Claim(ClaimTypes.Name, authenticatedUser.Name)); - if (authenticatedUser.IsAdmin) claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, PolicyNames.Admin)); - else if (authenticatedUser.IsViewer) claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, PolicyNames.Viewer)); - - return Task.FromResult(AuthenticateResult.Success( - new AuthenticationTicket(new ClaimsPrincipal(claimsIdentity), "BasicAuthentication"))); - } - - return Task.FromResult(AuthenticateResult.Fail("No valid authentication credentials has been provided.")); - } -} diff --git a/src/api/Authentication/DatabaseAuthenticationClaimsTranfomration.cs b/src/api/Authentication/DatabaseAuthenticationClaimsTranfomration.cs new file mode 100644 index 000000000..586ce77c0 --- /dev/null +++ b/src/api/Authentication/DatabaseAuthenticationClaimsTranfomration.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Authentication; +using System.Security.Claims; + +namespace BDMS.Authentication; + +public class DatabaseAuthenticationClaimsTranfomration : IClaimsTransformation +{ + private readonly BdmsContext dbContext; + + /// + /// Initializes a new instance of the class. + /// + /// The EF database context containing data for the BDMS application. + /// If is null. + public DatabaseAuthenticationClaimsTranfomration(BdmsContext dbContext) + { + this.dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); + } + + /// + public async Task TransformAsync(ClaimsPrincipal principal) + { + var userId = principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier); + var authenticatedUser = userId is not null ? dbContext.Users.FirstOrDefault(u => u.Name == userId.Value) : null; + + if (authenticatedUser == null || authenticatedUser.IsDisabled) + { + return principal; + } + + authenticatedUser.FirstName = principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value ?? authenticatedUser.FirstName; + authenticatedUser.LastName = principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value ?? authenticatedUser.LastName; + await dbContext.SaveChangesAsync().ConfigureAwait(false); + + var claimsIdentity = new ClaimsIdentity(); + claimsIdentity.AddClaim(new Claim(ClaimTypes.Name, authenticatedUser.Name)); + if (authenticatedUser.IsAdmin) claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, PolicyNames.Admin)); + else if (authenticatedUser.IsViewer) claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, PolicyNames.Viewer)); + + principal.AddIdentity(claimsIdentity); + return principal; + } +} diff --git a/src/api/BDMS.csproj b/src/api/BDMS.csproj index fcd48ab96..e3d4d4a7b 100644 --- a/src/api/BDMS.csproj +++ b/src/api/BDMS.csproj @@ -23,6 +23,7 @@ + diff --git a/src/api/Program.cs b/src/api/Program.cs index ca98858f4..f61bc2b79 100644 --- a/src/api/Program.cs +++ b/src/api/Program.cs @@ -3,8 +3,8 @@ using BDMS; using BDMS.Authentication; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Server.HttpSys; using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; using System.Reflection; @@ -21,6 +21,11 @@ }); builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => builder.Configuration.Bind("Auth", options)); + +builder.Services.AddTransient(); + builder.Services.AddAuthorization(options => { options.AddPolicy(PolicyNames.Admin, options => options.RequireRole(PolicyNames.Admin)); @@ -35,9 +40,6 @@ options.FallbackPolicy = options.DefaultPolicy; }); -builder.Services.AddAuthentication("BasicAuthentication") - .AddScheme("BasicAuthentication", null); - builder.Services.AddHttpContextAccessor(); builder.Services.AddHttpClient(); @@ -62,11 +64,10 @@ Version = "v2", Title = "BDMS REST API v2", }); - options.AddSecurityDefinition("Basic", new OpenApiSecurityScheme + options.AddSecurityDefinition("OpenIdConnect", new OpenApiSecurityScheme { In = ParameterLocation.Header, - Type = SecuritySchemeType.Http, - Scheme = nameof(AuthenticationSchemes.Basic), + Type = SecuritySchemeType.OpenIdConnect, }); options.AddSecurityRequirement(new OpenApiSecurityRequirement { @@ -76,7 +77,7 @@ Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, - Id = nameof(AuthenticationSchemes.Basic), + Id = nameof(SecuritySchemeType.OpenIdConnect), }, }, Array.Empty() diff --git a/src/api/appsettings.Development.json b/src/api/appsettings.Development.json index 2c102edfd..2ab8aaa39 100644 --- a/src/api/appsettings.Development.json +++ b/src/api/appsettings.Development.json @@ -15,6 +15,11 @@ "SECRET_KEY": "YELLOWMONKEY", "SECURE": "0" }, + "Auth": { + "Authority": "http://localhost:4011", + "Audience": "bdms-client", + "RequireHttpsMetadata": "false" + }, "ReverseProxy": { "Clusters": { "pythonApi": { From e5a2670146d42f0eba837c842cb6c97f8a3a5f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20L=C3=BCthi?= Date: Thu, 14 Dec 2023 11:56:56 +0100 Subject: [PATCH 03/31] Install react-oidc-context --- src/client/package-lock.json | 33 +++++++++++++++++++++++++++++++++ src/client/package.json | 2 ++ 2 files changed, 35 insertions(+) diff --git a/src/client/package-lock.json b/src/client/package-lock.json index 183513fb6..9b771cfd9 100644 --- a/src/client/package-lock.json +++ b/src/client/package-lock.json @@ -25,6 +25,7 @@ "lodash": "^4.17.21", "markdown-to-jsx": "^6.11.4", "moment": "^2.29.4", + "oidc-client-ts": "^3.0.0-beta.0", "ol": "^8.2.0", "proj4": "^2.9.2", "prop-types": "^15.8.1", @@ -37,6 +38,7 @@ "react-hook-form": "^7.48.2", "react-i18next": "^13.5.0", "react-number-format": "^5.3.1", + "react-oidc-context": "^3.0.0-beta.0", "react-query": "^3.39.3", "react-redux": "^7.2.9", "react-router-dom": "^5.3.4", @@ -11990,6 +11992,14 @@ "node": ">=4.0" } }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "engines": { + "node": ">=18" + } + }, "node_modules/keyboard-key": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.1.0.tgz", @@ -13051,6 +13061,17 @@ "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, + "node_modules/oidc-client-ts": { + "version": "3.0.0-beta.0", + "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-3.0.0-beta.0.tgz", + "integrity": "sha512-LXd4/w6kzYe0Hc2d+orHR9ACmRVgUOtWxOttca5DoZgvWU1tWlMbIKfiiKRRLOsHejc2y28Q+JhvGofK8gfXyQ==", + "dependencies": { + "jwt-decode": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/ol": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/ol/-/ol-8.2.0.tgz", @@ -15245,6 +15266,18 @@ "react-dom": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-oidc-context": { + "version": "3.0.0-beta.0", + "resolved": "https://registry.npmjs.org/react-oidc-context/-/react-oidc-context-3.0.0-beta.0.tgz", + "integrity": "sha512-Y3WjJ+2qBpNqkX7DTnYc2WRLhXajX2tCv2S5rSB05J9IOjAOBYPXArIlHbjp6UWnSBW8rGbobmoRB9clrqIcWg==", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "oidc-client-ts": "^3.0.0-beta.0", + "react": ">=16.8.0" + } + }, "node_modules/react-onclickoutside": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz", diff --git a/src/client/package.json b/src/client/package.json index 780f468b1..9336cae5b 100644 --- a/src/client/package.json +++ b/src/client/package.json @@ -39,6 +39,7 @@ "lodash": "^4.17.21", "markdown-to-jsx": "^6.11.4", "moment": "^2.29.4", + "oidc-client-ts": "^3.0.0-beta.0", "ol": "^8.2.0", "proj4": "^2.9.2", "prop-types": "^15.8.1", @@ -51,6 +52,7 @@ "react-hook-form": "^7.48.2", "react-i18next": "^13.5.0", "react-number-format": "^5.3.1", + "react-oidc-context": "^3.0.0-beta.0", "react-query": "^3.39.3", "react-redux": "^7.2.9", "react-router-dom": "^5.3.4", From a75c94b707e6cfbd62515d141c43f8927eca1762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20L=C3=BCthi?= Date: Thu, 14 Dec 2023 11:58:13 +0100 Subject: [PATCH 04/31] Implement oidc authentication in client --- src/client/src/api-lib/actions/index.js | 10 +- src/client/src/api-lib/actions/user.js | 10 +- src/client/src/api-lib/reducers/index.js | 6 +- src/client/src/api/authentication.js | 7 +- src/client/src/api/fetchApiV2.js | 9 +- src/client/src/commons/menu/menuComponent.js | 6 +- src/client/src/index.js | 19 ++- src/client/src/pages/settings/dataLoader.js | 131 +++---------------- 8 files changed, 53 insertions(+), 145 deletions(-) diff --git a/src/client/src/api-lib/actions/index.js b/src/client/src/api-lib/actions/index.js index 7bf7e57ad..180ac2f8b 100644 --- a/src/client/src/api-lib/actions/index.js +++ b/src/client/src/api-lib/actions/index.js @@ -1,6 +1,6 @@ import axios from "axios"; import store from "../reducers"; -import { getBasicAuthHeaderValue } from "../../api/authentication"; +import { getAuthorizationHeader } from "../../api/authentication"; function getAuthorizationHeaders(headers = {}) { if ( @@ -8,11 +8,8 @@ function getAuthorizationHeaders(headers = {}) { store.getState().hasOwnProperty("core_user") && store.getState().core_user.authentication !== null ) { - const credentials = store.getState().core_user.authentication; - headers.Authorization = getBasicAuthHeaderValue( - credentials.username, - credentials.password, - ); + const authentication = store.getState().core_user.authentication; + headers.Authorization = getAuthorizationHeader(authentication); headers["bdms-authorization"] = "bdms-v1"; } return headers; @@ -173,7 +170,6 @@ export function fetch(path, action, method = "post", auth = null) { resolve(response.data, dispatch); }) .catch(function (error) { - debugger; dispatch({ type: action.type + "_CONNECTION_ERROR", path: path, diff --git a/src/client/src/api-lib/actions/user.js b/src/client/src/api-lib/actions/user.js index 5e15d277b..143836d7d 100644 --- a/src/client/src/api-lib/actions/user.js +++ b/src/client/src/api-lib/actions/user.js @@ -1,16 +1,10 @@ import { fetch } from "./index"; -export function setAuthentication( - username, - password, - authentication = "basic", -) { +export function setAuthentication(user) { return { type: "SET_AUTHENTICATION", path: "/user", - username: username, - password: password, - authentication: authentication, + user: user, }; } diff --git a/src/client/src/api-lib/reducers/index.js b/src/client/src/api-lib/reducers/index.js index 20c2f0a12..9e8d5a5ea 100644 --- a/src/client/src/api-lib/reducers/index.js +++ b/src/client/src/api-lib/reducers/index.js @@ -19,11 +19,7 @@ export function user() { case "SET_AUTHENTICATION": { return { ...state, - authentication: { - username: action.username, - password: action.password, - type: action.authentication, - }, + authentication: action.user, }; } case "UNSET_AUTHENTICATION": { diff --git a/src/client/src/api/authentication.js b/src/client/src/api/authentication.js index cd2bef777..9cc060806 100644 --- a/src/client/src/api/authentication.js +++ b/src/client/src/api/authentication.js @@ -1,6 +1,3 @@ -export function getBasicAuthHeaderValue(username, password) { - const encoder = new TextEncoder(); - const data = encoder.encode(`${username}:${password}`); - const base64String = btoa(String.fromCharCode.apply(null, data)); - return `Basic ${base64String}`; +export function getAuthorizationHeader(authentication) { + return `${authentication.token_type} ${authentication.id_token}`; } diff --git a/src/client/src/api/fetchApiV2.js b/src/client/src/api/fetchApiV2.js index 596378054..8809cf825 100644 --- a/src/client/src/api/fetchApiV2.js +++ b/src/client/src/api/fetchApiV2.js @@ -1,6 +1,6 @@ import store from "../reducers"; import { useQuery, useMutation, useQueryClient } from "react-query"; -import { getBasicAuthHeaderValue } from "./authentication"; +import { getAuthorizationHeader } from "./authentication"; /** * Fetch data from the C# Api. @@ -19,13 +19,10 @@ export async function fetchApiV2( isFileDownload = false, ) { const baseUrl = "/api/v2/"; - const credentials = store.getState().core_user.authentication; + const authentication = store.getState().core_user.authentication; const body = isFileUpload ? payload : JSON.stringify(payload); let headers = { - Authorization: getBasicAuthHeaderValue( - credentials.username, - credentials.password, - ), + Authorization: getAuthorizationHeader(authentication), }; if (!isFileUpload && !isFileDownload) headers = { ...headers, "Content-Type": "application/json" }; diff --git a/src/client/src/commons/menu/menuComponent.js b/src/client/src/commons/menu/menuComponent.js index 4fb1dffcd..8dbe5421a 100644 --- a/src/client/src/commons/menu/menuComponent.js +++ b/src/client/src/commons/menu/menuComponent.js @@ -1,6 +1,7 @@ import React from "react"; import { connect } from "react-redux"; import PropTypes from "prop-types"; +import { withAuth } from "react-oidc-context"; import { withTranslation } from "react-i18next"; import _ from "lodash"; @@ -164,12 +165,11 @@ class MenuComponent extends React.Component { { + this.props.auth.removeUser(); this.props.unsetAuthentication(); if (_.isFunction(handleModeChange)) { handleModeChange("viewer"); } - // Clear cache - // window.location.reload(true); }}> Logout @@ -348,4 +348,4 @@ MenuComponent.propTypes = { export default connect( mapStateToProps, mapDispatchToProps, -)(withTranslation(["common"])(MenuComponent)); +)(withAuth(withTranslation(["common"])(MenuComponent))); diff --git a/src/client/src/index.js b/src/client/src/index.js index ac4b743ba..c13401592 100644 --- a/src/client/src/index.js +++ b/src/client/src/index.js @@ -1,4 +1,5 @@ import React from "react"; +import { AuthProvider } from "react-oidc-context"; import { createRoot } from "react-dom/client"; import { Provider } from "react-redux"; @@ -12,13 +13,29 @@ import "semantic-ui-css/semantic.css"; import store from "./reducers"; +const onSigninCallback = user => { + window.history.replaceState({}, document.title, window.location.pathname); + store.dispatch({ type: "SET_", user }); +}; + +const oidcConfig = { + // TODO: Use environment variables + authority: "http://localhost:4011", + client_id: "bdms-client", + scope: "openid profile email", + redirect_uri: window.location.origin, + onSigninCallback: onSigninCallback, +}; + const container = document.getElementById("root"); const root = createRoot(container); root.render( - + + + , ); diff --git a/src/client/src/pages/settings/dataLoader.js b/src/client/src/pages/settings/dataLoader.js index 8fd87149a..247e95ca6 100644 --- a/src/client/src/pages/settings/dataLoader.js +++ b/src/client/src/pages/settings/dataLoader.js @@ -1,12 +1,12 @@ -import React, { createRef } from "react"; +import React from "react"; import { connect } from "react-redux"; import PropTypes from "prop-types"; -import _ from "lodash"; import { withTranslation } from "react-i18next"; +import { withAuth } from "react-oidc-context"; import Markdown from "markdown-to-jsx"; import TranslationKeys from "../../commons/translationKeys"; -import { Button, Input } from "semantic-ui-react"; +import { Button } from "semantic-ui-react"; import { loadDomains, @@ -20,7 +20,6 @@ import { class DataLoader extends React.Component { constructor(props) { super(props); - this.fieldToRef = createRef(); this.state = { isFetching: true, title: { @@ -41,13 +40,6 @@ class DataLoader extends React.Component { } componentDidMount() { - if (process.env.NODE_ENV === "development") { - this.props.setAuthentication("admin", "swissforages"); - } else { - this.props.setAuthentication("", ""); - } - this.fieldToRef.current.focus(); - getContent("login").then(r => { if (r.data.data !== null) { this.setState({ @@ -60,7 +52,12 @@ class DataLoader extends React.Component { } componentDidUpdate(prevProps) { - if (!_.isEqual(this.props.user.data, prevProps.user.data)) { + if (this.props.auth.isAuthenticated && !this.props.user?.authentication) { + this.props.setAuthentication(this.props.auth.user); + } + + if (!prevProps.user?.authentication && this.props.user?.authentication) { + this.props.loadUser(); this.props.loadSettings(); this.props.loadDomains(); this.props.loadBoreholeCount(); @@ -68,6 +65,10 @@ class DataLoader extends React.Component { } render() { + const isLoading = + this.props.auth.isLoading || + this.props.auth.isAuthenticated || + this.props.user.authentication; return (
Sign in
- {/** Trick to disable autofill in chrome */} - -
- Username -
- { - this.props.setAuthentication( - e.target.value, - this.props.user.authentication !== null - ? this.props.user.authentication.password - : "", - ); - }} - onKeyPress={e => { - if (e.key === "Enter") { - this.props.loadUser(); - } - }} - placeholder="username" - ref={this.fieldToRef} - value={ - this.props.user.authentication !== null - ? this.props.user.authentication.username - : "" - } - /> - -
- Password -
- { - this.props.setAuthentication( - this.props.user.authentication !== null - ? this.props.user.authentication.username - : "", - e.target.value, - ); - }} - onKeyPress={e => { - if (e.key === "Enter") { - this.props.loadUser(); - } - }} - placeholder="password" - type="password" - value={ - this.props.user.authentication !== null - ? this.props.user.authentication.password - : "" - } - />