KEYCLOAK-10966: Integrate App-initiated actions in new acct console

This commit is contained in:
Stan Silvert 2019-08-01 13:23:22 -04:00 committed by Bruno Oliveira da Silva
parent e6fc9663f5
commit e2cac64c2c
6 changed files with 126 additions and 8 deletions

View file

@ -2,3 +2,5 @@
# 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

View file

@ -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}/>;

View file

@ -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);

View file

@ -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>
); );

View file

@ -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',

View file

@ -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',