KEYCLOAK-11550: Single page for credentials (initial commit)
This commit is contained in:
parent
685d49c693
commit
de6f90b43b
12 changed files with 289 additions and 34 deletions
|
@ -114,6 +114,12 @@ public class AccountConsole {
|
||||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||||
map.put("isEventsEnabled", eventStore != null && realm.isEventsEnabled());
|
map.put("isEventsEnabled", eventStore != null && realm.isEventsEnabled());
|
||||||
map.put("isAuthorizationEnabled", true);
|
map.put("isAuthorizationEnabled", true);
|
||||||
|
|
||||||
|
boolean isTotpConfigured = false;
|
||||||
|
if (user != null) {
|
||||||
|
isTotpConfigured = session.userCredentialManager().isConfiguredFor(realm, user, realm.getOTPPolicy().getType());
|
||||||
|
}
|
||||||
|
map.put("isTotpConfigured", isTotpConfigured);
|
||||||
|
|
||||||
FreeMarkerUtil freeMarkerUtil = new FreeMarkerUtil();
|
FreeMarkerUtil freeMarkerUtil = new FreeMarkerUtil();
|
||||||
String result = freeMarkerUtil.processTemplate(map, "index.ftl", theme);
|
String result = freeMarkerUtil.processTemplate(map, "index.ftl", theme);
|
||||||
|
|
|
@ -63,6 +63,7 @@ import java.util.Properties;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.keycloak.common.Profile;
|
import org.keycloak.common.Profile;
|
||||||
|
import org.keycloak.credential.CredentialModel;
|
||||||
import org.keycloak.theme.Theme;
|
import org.keycloak.theme.Theme;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -397,6 +398,17 @@ public class AccountRestService {
|
||||||
final ConsentRepresentation consent) {
|
final ConsentRepresentation consent) {
|
||||||
return upsert(clientId, consent);
|
return upsert(clientId, consent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Path("/totp/remove")
|
||||||
|
@DELETE
|
||||||
|
public Response removeTOTP() {
|
||||||
|
auth.require(AccountRoles.MANAGE_ACCOUNT);
|
||||||
|
|
||||||
|
session.userCredentialManager().disableCredentialType(realm, user, CredentialModel.OTP);
|
||||||
|
event.event(EventType.REMOVE_TOTP).client(auth.getClient()).user(auth.getUser()).success();
|
||||||
|
|
||||||
|
return Cors.add(request, Response.accepted()).build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates or updates the consent of the given, requested consent for
|
* Creates or updates the consent of the given, requested consent for
|
||||||
|
|
|
@ -31,7 +31,8 @@
|
||||||
isInternationalizationEnabled : ${realm.internationalizationEnabled?c},
|
isInternationalizationEnabled : ${realm.internationalizationEnabled?c},
|
||||||
isLinkedAccountsEnabled : ${realm.identityFederationEnabled?c},
|
isLinkedAccountsEnabled : ${realm.identityFederationEnabled?c},
|
||||||
isEventsEnabled : ${isEventsEnabled?c},
|
isEventsEnabled : ${isEventsEnabled?c},
|
||||||
isMyResourcesEnabled : ${(realm.userManagedAccessAllowed && isAuthorizationEnabled)?c}
|
isMyResourcesEnabled : ${(realm.userManagedAccessAllowed && isAuthorizationEnabled)?c},
|
||||||
|
isTotpConfigured : ${isTotpConfigured?c}
|
||||||
}
|
}
|
||||||
|
|
||||||
var availableLocales = [];
|
var availableLocales = [];
|
||||||
|
@ -229,8 +230,7 @@
|
||||||
<h6>${msg("accountSecurityIntroMessage")}</h6>
|
<h6>${msg("accountSecurityIntroMessage")}</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-c-card__body pf-c-content">
|
<div class="pf-c-card__body pf-c-content">
|
||||||
<h5 id="changePasswordLink"><a href="#/app/security/password">${msg("changePasswordHtmlTitle")}</a></h5>
|
<h5 id="signingInLink"><a href="#/app/security/signingin">${msg("signingIn")}</a></h5>
|
||||||
<h5 id="authenticatorLink"><a href="#/app/security/authenticator">${msg("authenticatorTitle")}</a></h5>
|
|
||||||
<h5 id="deviceActivityLink"><a href="#/app/security/device-activity">${msg("deviceActivityHtmlTitle")}</a></h5>
|
<h5 id="deviceActivityLink"><a href="#/app/security/device-activity">${msg("deviceActivityHtmlTitle")}</a></h5>
|
||||||
<h5 id="linkedAccountsLink" style="display:none"><a href="#/app/security/linked-accounts">${msg("linkedAccountsHtmlTitle")}</a></h5>
|
<h5 id="linkedAccountsLink" style="display:none"><a href="#/app/security/linked-accounts">${msg("linkedAccountsHtmlTitle")}</a></h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,6 +7,8 @@ continue=Continue
|
||||||
refreshPage=Refresh the page
|
refreshPage=Refresh the page
|
||||||
done=Done
|
done=Done
|
||||||
cancel=Cancel
|
cancel=Cancel
|
||||||
|
remove=Remove
|
||||||
|
update=Update
|
||||||
|
|
||||||
# Device Activity Page
|
# Device Activity Page
|
||||||
signedInDevices=Signed In Devices
|
signedInDevices=Signed In Devices
|
||||||
|
@ -53,3 +55,16 @@ systemDefined=System Defined
|
||||||
link=Link Account
|
link=Link Account
|
||||||
unLink=Unlink Account
|
unLink=Unlink Account
|
||||||
|
|
||||||
|
# Signing In Page
|
||||||
|
signingIn=Signing In
|
||||||
|
signingInSubMessage=Configure ways to sign in.
|
||||||
|
twoFactorEnabled=Two-factor authentication is enabled.
|
||||||
|
twoFactorDisabled=Two-factor authentication is disabled.
|
||||||
|
twoFactorAuth=Two-Factor Authentication
|
||||||
|
mobileAuthDefault=Mobile Authenticator (Default)
|
||||||
|
removeMobileAuth=Remove Mobile Authenticator
|
||||||
|
stopMobileAuth=Stop using Mobile Authenticator?
|
||||||
|
setUp=Set Up
|
||||||
|
passwordless=Passwordless
|
||||||
|
lastUpdate=Last Update
|
||||||
|
unknown=Unknown
|
||||||
|
|
|
@ -26,6 +26,7 @@ module.exports = {
|
||||||
"@typescript-eslint/no-empty-interface": "off",
|
"@typescript-eslint/no-empty-interface": "off",
|
||||||
"@typescript-eslint/no-non-null-assertion": "off",
|
"@typescript-eslint/no-non-null-assertion": "off",
|
||||||
"@typescript-eslint/no-parameter-properties": "off",
|
"@typescript-eslint/no-parameter-properties": "off",
|
||||||
|
"@typescript-eslint/explicit-member-accessibility": "off",
|
||||||
"no-restricted-properties": "off"
|
"no-restricted-properties": "off"
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {withRouter, RouteComponentProps} from 'react-router-dom';
|
import {withRouter, RouteComponentProps} from 'react-router-dom';
|
||||||
|
|
||||||
|
import {AIACommand} from '../../util/AIACommand';
|
||||||
import {PageDef} from '../../ContentPages';
|
import {PageDef} from '../../ContentPages';
|
||||||
import {Msg} from '../../widgets/Msg';
|
import {Msg} from '../../widgets/Msg';
|
||||||
|
|
||||||
|
@ -47,11 +48,6 @@ interface AppInitiatedActionPageProps extends RouteComponentProps {
|
||||||
pageDef: ActionPageDef;
|
pageDef: ActionPageDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const baseUrl: string;
|
|
||||||
declare const realm: string;
|
|
||||||
declare const referrer: string;
|
|
||||||
declare const referrerUri: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Stan Silvert
|
* @author Stan Silvert
|
||||||
*/
|
*/
|
||||||
|
@ -62,28 +58,7 @@ class ApplicationInitiatedActionPage extends React.Component<AppInitiatedActionP
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleClick = (): void => {
|
private handleClick = (): void => {
|
||||||
let redirectURI: string = baseUrl;
|
new AIACommand(this.props.pageDef.kcAction, this.props.location.pathname).execute();
|
||||||
|
|
||||||
if (typeof referrer !== 'undefined') {
|
|
||||||
// '_hash_' is a workaround for when uri encoding is not
|
|
||||||
// sufficient to escape the # character properly.
|
|
||||||
// The problem is that both the redirect and the application URL contain a hash.
|
|
||||||
// The browser will consider anything after the first hash to be client-side. So
|
|
||||||
// it sees the hash in the redirect param and stops.
|
|
||||||
redirectURI += "?referrer=" + referrer + "&referrer_uri=" + referrerUri.replace('#', '_hash_');
|
|
||||||
}
|
|
||||||
|
|
||||||
redirectURI = encodeURIComponent(redirectURI);
|
|
||||||
|
|
||||||
const href: string = "/auth/realms/" + realm +
|
|
||||||
"/protocol/openid-connect/auth/" +
|
|
||||||
"?response_type=code" +
|
|
||||||
"&client_id=account&scope=openid" +
|
|
||||||
"&kc_action=" + this.props.pageDef.kcAction +
|
|
||||||
"&redirect_uri=" + redirectURI +
|
|
||||||
encodeURIComponent("/#" + this.props.location.pathname); // return to this page
|
|
||||||
|
|
||||||
window.location.href = href;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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 * as React from 'react';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
import {AxiosResponse} from 'axios';
|
||||||
|
|
||||||
|
import {withRouter, RouteComponentProps} from 'react-router-dom';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
DataList,
|
||||||
|
DataListAction,
|
||||||
|
DataListItemCells,
|
||||||
|
DataListCell,
|
||||||
|
DataListItemRow,
|
||||||
|
Stack,
|
||||||
|
StackItem,
|
||||||
|
Switch,
|
||||||
|
Title,
|
||||||
|
TitleLevel
|
||||||
|
} from '@patternfly/react-core';
|
||||||
|
|
||||||
|
import {AIACommand} from '../../util/AIACommand';
|
||||||
|
import {AccountServiceClient} from '../../account-service/account.service';
|
||||||
|
import {ContinueCancelModal} from '../../widgets/ContinueCancelModal';
|
||||||
|
import {Features} from '../../widgets/features';
|
||||||
|
import {Msg} from '../../widgets/Msg';
|
||||||
|
import {ContentPage} from '../ContentPage';
|
||||||
|
import {ContentAlert} from '../ContentAlert';
|
||||||
|
|
||||||
|
declare const features: Features;
|
||||||
|
|
||||||
|
interface PasswordDetails {
|
||||||
|
registered: boolean;
|
||||||
|
lastUpdate: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SigningInPageProps extends RouteComponentProps {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SigningInPageState {
|
||||||
|
twoFactorEnabled: boolean;
|
||||||
|
twoFactorEnabledText: string;
|
||||||
|
isTotpConfigured: boolean;
|
||||||
|
lastPasswordUpdate?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
class SigningInPage extends React.Component<SigningInPageProps, SigningInPageState> {
|
||||||
|
private readonly updatePassword: AIACommand = new AIACommand('UPDATE_PASSWORD', this.props.location.pathname);
|
||||||
|
private readonly setUpTOTP: AIACommand = new AIACommand('CONFIGURE_TOTP', this.props.location.pathname);
|
||||||
|
|
||||||
|
public constructor(props: SigningInPageProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
twoFactorEnabled: true,
|
||||||
|
twoFactorEnabledText: Msg.localize('twoFactorEnabled'),
|
||||||
|
isTotpConfigured: features.isTotpConfigured,
|
||||||
|
}
|
||||||
|
this.setLastPwdUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private setLastPwdUpdate(): void {
|
||||||
|
AccountServiceClient.Instance.doGet("/credentials/password")
|
||||||
|
.then((response: AxiosResponse<PasswordDetails>) => {
|
||||||
|
if (response.data.lastUpdate) {
|
||||||
|
const lastUpdate: number = response.data.lastUpdate;
|
||||||
|
this.setState({lastPasswordUpdate: lastUpdate});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTwoFactorSwitch = () => {
|
||||||
|
if (this.state.twoFactorEnabled) {
|
||||||
|
this.setState({twoFactorEnabled: false, twoFactorEnabledText: Msg.localize('twoFactorDisabled')})
|
||||||
|
} else {
|
||||||
|
this.setState({twoFactorEnabled: true, twoFactorEnabledText: Msg.localize('twoFactorEnabled')})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRemoveTOTP = () => {
|
||||||
|
AccountServiceClient.Instance.doDelete("/totp/remove")
|
||||||
|
.then(() => {
|
||||||
|
this.setState({isTotpConfigured: false});
|
||||||
|
ContentAlert.success('successTotpRemovedMessage');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): React.ReactNode {
|
||||||
|
let lastPwdUpdate: string = Msg.localize('unknown');
|
||||||
|
if (this.state.lastPasswordUpdate) {
|
||||||
|
lastPwdUpdate = moment(this.state.lastPasswordUpdate).format('LLL');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ContentPage title="signingIn"
|
||||||
|
introMessage="signingInSubMessage">
|
||||||
|
<Stack gutter='md'>
|
||||||
|
<StackItem isFilled>
|
||||||
|
<Title headingLevel={TitleLevel.h2} size='2xl'>
|
||||||
|
<strong><Msg msgKey='password'/></strong>
|
||||||
|
</Title>
|
||||||
|
<DataList aria-label='foo'>
|
||||||
|
<DataListItemRow>
|
||||||
|
<DataListItemCells
|
||||||
|
dataListCells={[
|
||||||
|
<DataListCell key='password'><Msg msgKey='password'/></DataListCell>,
|
||||||
|
<DataListCell key='lastPwdUpdate'><strong><Msg msgKey='lastUpdate'/>: </strong>{lastPwdUpdate}</DataListCell>,
|
||||||
|
<DataListCell key='spacer'/>
|
||||||
|
]}/>
|
||||||
|
<DataListAction aria-labelledby='foo' aria-label='foo action' id='setPasswordAction'>
|
||||||
|
<Button variant='primary'onClick={()=> this.updatePassword.execute()}><Msg msgKey='update'/></Button>
|
||||||
|
</DataListAction>
|
||||||
|
</DataListItemRow>
|
||||||
|
</DataList>
|
||||||
|
</StackItem>
|
||||||
|
<StackItem isFilled>
|
||||||
|
<Title headingLevel={TitleLevel.h2} size='2xl'>
|
||||||
|
<strong><Msg msgKey='twoFactorAuth'/></strong>
|
||||||
|
</Title>
|
||||||
|
<DataList aria-label='foo'>
|
||||||
|
<DataListItemRow>
|
||||||
|
<DataListAction aria-labelledby='foo' aria-label='foo action' id='twoFactorOnOff'>
|
||||||
|
<Switch
|
||||||
|
aria-label='twoFactorSwitch'
|
||||||
|
label={this.state.twoFactorEnabledText}
|
||||||
|
isChecked={this.state.twoFactorEnabled}
|
||||||
|
onClick={this.handleTwoFactorSwitch}
|
||||||
|
/>
|
||||||
|
</DataListAction>
|
||||||
|
</DataListItemRow>
|
||||||
|
<DataListItemRow>
|
||||||
|
<DataListItemCells
|
||||||
|
dataListCells={[
|
||||||
|
<DataListCell key='mobileAuth'><Msg msgKey='mobileAuthDefault'/></DataListCell>
|
||||||
|
]}/>
|
||||||
|
{!this.state.isTotpConfigured &&
|
||||||
|
<DataListAction aria-labelledby='foo' aria-label='foo action' id='setMobileAuthAction'>
|
||||||
|
<Button isDisabled={!this.state.twoFactorEnabled} variant='primary' onClick={()=> this.setUpTOTP.execute()}><Msg msgKey='setUp'/></Button>
|
||||||
|
</DataListAction>
|
||||||
|
}
|
||||||
|
{this.state.isTotpConfigured &&
|
||||||
|
<DataListAction aria-labelledby='foo' aria-label='foo action' id='setMobileAuthAction'>
|
||||||
|
<ContinueCancelModal buttonTitle='remove'
|
||||||
|
isDisabled={!this.state.twoFactorEnabled}
|
||||||
|
modalTitle={Msg.localize('removeMobileAuth')}
|
||||||
|
modalMessage={Msg.localize('stopMobileAuth')}
|
||||||
|
onContinue={this.handleRemoveTOTP}
|
||||||
|
/>
|
||||||
|
</DataListAction>
|
||||||
|
}
|
||||||
|
</DataListItemRow>
|
||||||
|
</DataList>
|
||||||
|
</StackItem>
|
||||||
|
<StackItem isFilled>
|
||||||
|
<Title headingLevel={TitleLevel.h2} size='2xl'>
|
||||||
|
<strong><Msg msgKey='passwordless'/></strong>
|
||||||
|
</Title>
|
||||||
|
</StackItem>
|
||||||
|
</Stack>
|
||||||
|
</ContentPage>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const SigningInPageWithRouter = withRouter(SigningInPage);
|
||||||
|
export { SigningInPageWithRouter as SigningInPage};
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
declare const baseUrl: string;
|
||||||
|
declare const realm: string;
|
||||||
|
declare const referrer: string;
|
||||||
|
declare const referrerUri: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Stan Silvert
|
||||||
|
*/
|
||||||
|
export class AIACommand {
|
||||||
|
constructor(private action: string, private redirectPath: string) {}
|
||||||
|
|
||||||
|
public execute(): void {
|
||||||
|
let redirectURI: string = baseUrl;
|
||||||
|
|
||||||
|
if (typeof referrer !== 'undefined') {
|
||||||
|
// '_hash_' is a workaround for when uri encoding is not
|
||||||
|
// sufficient to escape the # character properly.
|
||||||
|
// The problem is that both the redirect and the application URL contain a hash.
|
||||||
|
// The browser will consider anything after the first hash to be client-side. So
|
||||||
|
// it sees the hash in the redirect param and stops.
|
||||||
|
redirectURI += "?referrer=" + referrer + "&referrer_uri=" + referrerUri.replace('#', '_hash_');
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectURI = encodeURIComponent(redirectURI);
|
||||||
|
|
||||||
|
const href: string = "/auth/realms/" + realm +
|
||||||
|
"/protocol/openid-connect/auth/" +
|
||||||
|
"?response_type=code" +
|
||||||
|
"&client_id=account&scope=openid" +
|
||||||
|
"&kc_action=" + this.action +
|
||||||
|
"&redirect_uri=" + redirectURI +
|
||||||
|
encodeURIComponent("/#" + this.redirectPath); // return to this page
|
||||||
|
|
||||||
|
window.location.href = href;
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ interface ContinueCancelModalProps {
|
||||||
modalContinueButtonLabel?: string;
|
modalContinueButtonLabel?: string;
|
||||||
modalCancelButtonLabel?: string;
|
modalCancelButtonLabel?: string;
|
||||||
onContinue: () => void;
|
onContinue: () => void;
|
||||||
|
isDisabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ContinueCancelModalState {
|
interface ContinueCancelModalState {
|
||||||
|
@ -46,7 +47,8 @@ export class ContinueCancelModal extends React.Component<ContinueCancelModalProp
|
||||||
protected static defaultProps = {
|
protected static defaultProps = {
|
||||||
buttonVariant: 'primary',
|
buttonVariant: 'primary',
|
||||||
modalContinueButtonLabel: 'continue',
|
modalContinueButtonLabel: 'continue',
|
||||||
modalCancelButtonLabel: 'doCancel'
|
modalCancelButtonLabel: 'doCancel',
|
||||||
|
isDisabled: false
|
||||||
};
|
};
|
||||||
|
|
||||||
public constructor(props: ContinueCancelModalProps) {
|
public constructor(props: ContinueCancelModalProps) {
|
||||||
|
@ -72,7 +74,7 @@ export class ContinueCancelModal extends React.Component<ContinueCancelModalProp
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Button variant={this.props.buttonVariant} onClick={this.handleModalToggle}>
|
<Button variant={this.props.buttonVariant} onClick={this.handleModalToggle} isDisabled={this.props.isDisabled}>
|
||||||
<Msg msgKey={this.props.buttonTitle}/>
|
<Msg msgKey={this.props.buttonTitle}/>
|
||||||
</Button>
|
</Button>
|
||||||
<Modal
|
<Modal
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
isLinkedAccountsEnabled: boolean;
|
isLinkedAccountsEnabled: boolean;
|
||||||
isEventsEnabled: boolean;
|
isEventsEnabled: boolean;
|
||||||
isMyResourcesEnabled: boolean;
|
isMyResourcesEnabled: boolean;
|
||||||
|
isTotpConfigured: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,12 @@ var content = [
|
||||||
label: 'Account Security',
|
label: 'Account Security',
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
|
path: 'security/signingin',
|
||||||
|
label: 'signingIn',
|
||||||
|
modulePath: '/app/content/signingin-page/SigningInPage',
|
||||||
|
componentName: 'SigningInPage',
|
||||||
|
},
|
||||||
|
/* {
|
||||||
path: 'security/password',
|
path: 'security/password',
|
||||||
label: 'password',
|
label: 'password',
|
||||||
modulePath: '/app/content/aia-page/AppInitiatedActionPage',
|
modulePath: '/app/content/aia-page/AppInitiatedActionPage',
|
||||||
|
@ -22,7 +28,7 @@ var content = [
|
||||||
modulePath: '/app/content/aia-page/AppInitiatedActionPage',
|
modulePath: '/app/content/aia-page/AppInitiatedActionPage',
|
||||||
componentName: 'AppInitiatedActionPage',
|
componentName: 'AppInitiatedActionPage',
|
||||||
kcAction: 'CONFIGURE_TOTP'
|
kcAction: 'CONFIGURE_TOTP'
|
||||||
},
|
}, */
|
||||||
{
|
{
|
||||||
path: 'security/device-activity',
|
path: 'security/device-activity',
|
||||||
label: 'device-activity',
|
label: 'device-activity',
|
||||||
|
|
|
@ -120,7 +120,7 @@
|
||||||
'./Radio': '@empty', //'./Radio/index.js',
|
'./Radio': '@empty', //'./Radio/index.js',
|
||||||
'./Select': '@empty', //'./Select/index.js',
|
'./Select': '@empty', //'./Select/index.js',
|
||||||
'./SkipToContent': '@empty', //'./SkipToContent/index.js',
|
'./SkipToContent': '@empty', //'./SkipToContent/index.js',
|
||||||
'./Switch': '@empty', //'./Switch/index.js',
|
'./Switch': './Switch/index.js',
|
||||||
'./Tabs': './Tabs/index.js', //'./Tabs/index.js',
|
'./Tabs': './Tabs/index.js', //'./Tabs/index.js',
|
||||||
'./Text': '@empty', //'./Text/index.js',
|
'./Text': '@empty', //'./Text/index.js',
|
||||||
'./TextArea': '@empty', //'./TextArea/index.js',
|
'./TextArea': '@empty', //'./TextArea/index.js',
|
||||||
|
|
Loading…
Reference in a new issue