KEYCLOAK-10966: Integrate App-initiated actions in new acct console
This commit is contained in:
parent
e6fc9663f5
commit
e2cac64c2c
6 changed files with 126 additions and 8 deletions
|
@ -1,4 +1,6 @@
|
||||||
# Put new messages for Account Console Here
|
# Put new messages for Account Console Here
|
||||||
# Feel free to use any existing messages from the base theme
|
# Feel free to use any existing messages from the base theme
|
||||||
pageNotFound=Page Not Found
|
pageNotFound=Page Not Found
|
||||||
invalidRoute={0} is not a valid route.
|
invalidRoute={0} is not a valid route.
|
||||||
|
actionRequiresIDP=This action requires redirection to your identity provider.
|
||||||
|
continue=Continue
|
|
@ -153,7 +153,8 @@ export function makeRoutes(): React.ReactNode {
|
||||||
|
|
||||||
const routes: React.ReactElement<Route>[] = pageDefs.map((page: PageDef) => {
|
const routes: React.ReactElement<Route>[] = pageDefs.map((page: PageDef) => {
|
||||||
if (isModulePageDef(page)) {
|
if (isModulePageDef(page)) {
|
||||||
return <Route key={page.itemId} path={'/app/' + page.path} exact component={page.module[page.componentName]}/>;
|
const node: React.ReactNode = React.createElement(page.module[page.componentName], {'pageDef': page});
|
||||||
|
return <Route key={page.itemId} path={'/app/' + page.path} exact render={() => node} />;
|
||||||
} else {
|
} else {
|
||||||
const pageDef: ComponentPageDef = page as ComponentPageDef;
|
const pageDef: ComponentPageDef = page as ComponentPageDef;
|
||||||
return <Route key={page.itemId} path={'/app/' + page.path} exact component={pageDef.component}/>;
|
return <Route key={page.itemId} path={'/app/' + page.path} exact component={pageDef.component}/>;
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import {withRouter, RouteComponentProps} from 'react-router-dom';
|
||||||
|
|
||||||
|
import {PageDef} from '../../ContentPages';
|
||||||
|
import {Msg} from '../../widgets/Msg';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Title,
|
||||||
|
TitleLevel,
|
||||||
|
Button,
|
||||||
|
EmptyState,
|
||||||
|
EmptyStateVariant,
|
||||||
|
EmptyStateIcon,
|
||||||
|
EmptyStateBody
|
||||||
|
} from '@patternfly/react-core';
|
||||||
|
import { PassportIcon } from '@patternfly/react-icons';
|
||||||
|
|
||||||
|
// Note: This class demonstrates two features of the ContentPages framework:
|
||||||
|
// 1) The PageDef is available as a React property.
|
||||||
|
// 2) You can add additional custom properties to the PageDef. In this case,
|
||||||
|
// we add a value called kcAction in content.js and access it by extending the
|
||||||
|
// PageDef interface.
|
||||||
|
interface ActionPageDef extends PageDef {
|
||||||
|
kcAction: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend RouteComponentProps to get access to router information such as
|
||||||
|
// the hash-routed path associated with this page. See this.props.location.pathname
|
||||||
|
// as used below.
|
||||||
|
interface AppInitiatedActionPageProps extends RouteComponentProps {
|
||||||
|
pageDef: ActionPageDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const baseUrl: string;
|
||||||
|
declare const realm: string;
|
||||||
|
declare const referrer: string;
|
||||||
|
declare const referrerUri: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Stan Silvert
|
||||||
|
*/
|
||||||
|
class ApplicationInitiatedActionPage extends React.Component<AppInitiatedActionPageProps> {
|
||||||
|
|
||||||
|
public constructor(props: AppInitiatedActionPageProps) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleClick = (): 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.props.pageDef.kcAction +
|
||||||
|
"&silent_cancel=true" +
|
||||||
|
"&redirect_uri=" + redirectURI +
|
||||||
|
encodeURIComponent("/#" + this.props.location.pathname); // return to this page
|
||||||
|
|
||||||
|
window.location.href = href;
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): React.ReactNode {
|
||||||
|
return (
|
||||||
|
<EmptyState variant={EmptyStateVariant.full}>
|
||||||
|
<EmptyStateIcon icon={PassportIcon} />
|
||||||
|
<Title headingLevel={TitleLevel.h5} size="lg">
|
||||||
|
<Msg msgKey={this.props.pageDef.label} params={this.props.pageDef.labelParams}/>
|
||||||
|
</Title>
|
||||||
|
<EmptyStateBody>
|
||||||
|
<Msg msgKey="actionRequiresIDP"/>
|
||||||
|
</EmptyStateBody>
|
||||||
|
<Button variant="primary"
|
||||||
|
onClick={this.handleClick}
|
||||||
|
target="_blank"><Msg msgKey="continue"/></Button>
|
||||||
|
</EmptyState>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Note that the class name is not exported above. To get access to the router,
|
||||||
|
// we use withRouter() and export a different name.
|
||||||
|
export const AppInitiatedActionPage = withRouter(ApplicationInitiatedActionPage);
|
|
@ -37,7 +37,10 @@ export class ReferrerLink extends React.Component<ReferrerLinkProps> {
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
return (
|
return (
|
||||||
<a href={referrerUri}>
|
// '_hash_' is a workaround for when uri encoding is not
|
||||||
|
// sufficient to escape the # character properly.
|
||||||
|
// See AppInitiatedActionPage for more details.
|
||||||
|
<a href={referrerUri.replace('_hash_', '#')}>
|
||||||
<ArrowIcon/> <Msg msgKey="backTo" params={[referrerName]}/>
|
<ArrowIcon/> <Msg msgKey="backTo" params={[referrerName]}/>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,14 +12,16 @@ var content = [
|
||||||
{
|
{
|
||||||
path: 'security/password',
|
path: 'security/password',
|
||||||
label: 'password',
|
label: 'password',
|
||||||
modulePath: '/app/content/password-page/PasswordPage',
|
modulePath: '/app/content/aia-page/AppInitiatedActionPage',
|
||||||
componentName: 'PasswordPage'
|
componentName: 'AppInitiatedActionPage',
|
||||||
|
kcAction: 'update_password'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'security/authenticator',
|
path: 'security/authenticator',
|
||||||
label: 'authenticator',
|
label: 'authenticator',
|
||||||
modulePath: '/app/content/authenticator-page/AuthenticatorPage',
|
modulePath: '/app/content/aia-page/AppInitiatedActionPage',
|
||||||
componentName: 'AuthenticatorPage'
|
componentName: 'AppInitiatedActionPage',
|
||||||
|
kcAction: 'configure_totp'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'security/device-activity',
|
path: 'security/device-activity',
|
||||||
|
|
|
@ -769,7 +769,7 @@
|
||||||
'./icons/parachute-box-icon.js': '@empty',
|
'./icons/parachute-box-icon.js': '@empty',
|
||||||
'./icons/paragraph-icon.js': '@empty',
|
'./icons/paragraph-icon.js': '@empty',
|
||||||
'./icons/parking-icon.js': '@empty',
|
'./icons/parking-icon.js': '@empty',
|
||||||
'./icons/passport-icon.js': '@empty',
|
//'./icons/passport-icon.js': '@empty',
|
||||||
'./icons/pastafarianism-icon.js': '@empty',
|
'./icons/pastafarianism-icon.js': '@empty',
|
||||||
'./icons/paste-icon.js': '@empty',
|
'./icons/paste-icon.js': '@empty',
|
||||||
'./icons/pause-icon.js': '@empty',
|
'./icons/pause-icon.js': '@empty',
|
||||||
|
|
Loading…
Reference in a new issue