Add support for security keys password

This commit is contained in:
Pierre HUBERT 2021-07-11 17:55:47 +02:00
parent 0cd6de200d
commit b7b1962886
4 changed files with 66 additions and 14 deletions

View File

@ -15,10 +15,12 @@ export interface AdminAccountKey {
id: number;
name: string;
time_add: number;
has_password: boolean;
}
export interface AuthKey {
name: string;
id: number;
password: boolean;
}
export class AdminKeyHelper {
@ -42,8 +44,13 @@ export class AdminKeyHelper {
*
* @param name The name of the key to create
* @param cred The credentials to register
* @param password The password required to use the key
*/
static async RegisterKey(name: string, cred: any): Promise<void> {
static async RegisterKey(
name: string,
cred: any,
password: string
): Promise<void> {
const res = {
id: cred.id,
rawId: ArrayBufferToBase64(cred.rawId),
@ -61,6 +68,7 @@ export class AdminKeyHelper {
await serverRequest("keys/register_key", {
name: name,
key: JSON.stringify(res),
password: password,
});
}
@ -96,11 +104,13 @@ export class AdminKeyHelper {
* @param mail Target admin account email address
* @param key Key used to authenticate
* @param cred Response to authentication
* @param password The password associated with the key (if any)
*/
static async AuthenticateWithKey(
mail: string,
key: AuthKey,
cred: any
cred: any,
password: string
): Promise<any> {
const creds = {
id: cred.id,
@ -122,6 +132,7 @@ export class AdminKeyHelper {
mail: mail,
key_id: key.id,
credential: JSON.stringify(creds),
password: password,
});
sessionStorage.setItem(SESSION_STORAGE_TOKEN, res.token);

View File

@ -1,24 +1,26 @@
import {
Button,
Divider,
IconButton,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
TableCell,
TableBody,
IconButton,
Divider,
Button,
Tooltip,
} from "@material-ui/core";
import { Delete } from "@material-ui/icons";
import LockIcon from "@material-ui/icons/Lock";
import React from "react";
import { AdminAccount, AccountHelper } from "../../helpers/AccountHelper";
import { AccountHelper, AdminAccount } from "../../helpers/AccountHelper";
import { AdminAccountKey, AdminKeyHelper } from "../../helpers/AdminKeyHelper";
import { CopyToClipboard } from "../../utils/ClipboardUtils";
import { AsyncWidget } from "../widgets/AsyncWidget";
import {
input,
matAlert,
matConfirm,
snackbar,
matAlert,
input,
} from "../widgets/DialogsProvider";
import { TimestampWidget } from "../widgets/TimestampWidget";
import { SettingsSection } from "./SettingsSection";
@ -83,7 +85,14 @@ export class KeySettingsSection extends React.Component<
minLength: 2,
});
await AdminKeyHelper.RegisterKey(name, credential);
const password = await input({
label: "Key password (10 characters min)",
maxLength: 4000,
minLength: 10,
type: "password",
});
await AdminKeyHelper.RegisterKey(name, credential, password);
snackbar("Successfully enrolled a new key!");
@ -139,7 +148,19 @@ export class KeySettingsSection extends React.Component<
{this.state.keys.map((key) => (
<TableRow key={key.id}>
<TableCell component="th" scope="row">
{key.name}
{key.name}{" "}
{key.has_password ? (
<Tooltip
disableFocusListener
title="This key requires a password to be used"
placement="top"
arrow
>
<LockIcon fontSize="inherit" />
</Tooltip>
) : (
<></>
)}
</TableCell>
<TableCell align="right">
<TimestampWidget time={key.time_add} />

View File

@ -24,6 +24,7 @@ import React from "react";
import { AccountHelper, AuthOptions } from "../../helpers/AccountHelper";
import { AdminKeyHelper, AuthKey } from "../../helpers/AdminKeyHelper";
import { input, matAlert } from "../widgets/DialogsProvider";
import LockIcon from "@material-ui/icons/Lock";
function ErrorGettingOptions(p: { message: string }) {
return (
@ -248,10 +249,22 @@ class AuthOptionsWidget extends React.Component<
const result = await navigator.credentials.get(challenge);
const password = key.password
? await input({
label: "Key password",
message:
"A password is required to sign in using this key.",
minLength: 2,
title: "Login with " + key.name,
type: "password",
})
: "";
await AdminKeyHelper.AuthenticateWithKey(
this.props.email,
key,
result
result,
password
);
document.location.href = document.location.href + "";
@ -304,7 +317,12 @@ class AuthOptionsWidget extends React.Component<
</ListItemAvatar>
<ListItemText
primary={key.name}
secondary="Sign in using this security key"
secondary={
"Sign in using this security key. " +
(key.password
? "A password is associated with this key."
: "")
}
/>
</ListItem>
))}

View File

@ -27,6 +27,7 @@ export interface TextInputOptions {
minLength?: number;
maxLength?: number;
label: string;
type?: string;
}
interface AppDiagProvState {
@ -287,6 +288,7 @@ export class ApplicationDialogsProvider extends React.Component<
variant="outlined"
value={this.state.inputValue}
onChange={this.handleInputValueChanged}
type={this.state.inputOptions.type || "text"}
/>
</DialogContent>
<DialogActions>