From e2cac64c2c2370a6b40a335581bf43c19fa21c8c Mon Sep 17 00:00:00 2001 From: Stan Silvert Date: Thu, 1 Aug 2019 13:23:22 -0400 Subject: [PATCH] KEYCLOAK-10966: Integrate App-initiated actions in new acct console --- .../account/messages/messages_en.properties | 4 +- .../account/resources/app/ContentPages.tsx | 3 +- .../aia-page/AppInitiatedActionPage.tsx | 110 ++++++++++++++++++ .../resources/app/widgets/ReferrerLink.tsx | 5 +- .../account/resources/content.js | 10 +- .../account/resources/systemjs.config.js | 2 +- 6 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/aia-page/AppInitiatedActionPage.tsx diff --git a/themes/src/main/resources/theme/keycloak-preview/account/messages/messages_en.properties b/themes/src/main/resources/theme/keycloak-preview/account/messages/messages_en.properties index d168d0357d..fb00ab4f41 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/messages/messages_en.properties +++ b/themes/src/main/resources/theme/keycloak-preview/account/messages/messages_en.properties @@ -1,4 +1,6 @@ # Put new messages for Account Console Here # Feel free to use any existing messages from the base theme pageNotFound=Page Not Found -invalidRoute={0} is not a valid route. \ No newline at end of file +invalidRoute={0} is not a valid route. +actionRequiresIDP=This action requires redirection to your identity provider. +continue=Continue \ No newline at end of file diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/ContentPages.tsx b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/ContentPages.tsx index 5926e62290..4bb0255085 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/ContentPages.tsx +++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/ContentPages.tsx @@ -153,7 +153,8 @@ export function makeRoutes(): React.ReactNode { const routes: React.ReactElement[] = pageDefs.map((page: PageDef) => { if (isModulePageDef(page)) { - return ; + const node: React.ReactNode = React.createElement(page.module[page.componentName], {'pageDef': page}); + return node} />; } else { const pageDef: ComponentPageDef = page as ComponentPageDef; return ; diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/aia-page/AppInitiatedActionPage.tsx b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/aia-page/AppInitiatedActionPage.tsx new file mode 100644 index 0000000000..34e7392b6a --- /dev/null +++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/aia-page/AppInitiatedActionPage.tsx @@ -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 { + + 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 ( + + + + <Msg msgKey={this.props.pageDef.label} params={this.props.pageDef.labelParams}/> + + + + + + + ); + } +}; + +// 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); \ No newline at end of file diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/widgets/ReferrerLink.tsx b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/widgets/ReferrerLink.tsx index 872893159d..1a81a77b87 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/widgets/ReferrerLink.tsx +++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/widgets/ReferrerLink.tsx @@ -37,7 +37,10 @@ export class ReferrerLink extends React.Component { public render(): React.ReactNode { return ( - + // '_hash_' is a workaround for when uri encoding is not + // sufficient to escape the # character properly. + // See AppInitiatedActionPage for more details. + ); diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/content.js b/themes/src/main/resources/theme/keycloak-preview/account/resources/content.js index 6d68df74d3..6617caa85d 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/resources/content.js +++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/content.js @@ -12,14 +12,16 @@ var content = [ { path: 'security/password', label: 'password', - modulePath: '/app/content/password-page/PasswordPage', - componentName: 'PasswordPage' + modulePath: '/app/content/aia-page/AppInitiatedActionPage', + componentName: 'AppInitiatedActionPage', + kcAction: 'update_password' }, { path: 'security/authenticator', label: 'authenticator', - modulePath: '/app/content/authenticator-page/AuthenticatorPage', - componentName: 'AuthenticatorPage' + modulePath: '/app/content/aia-page/AppInitiatedActionPage', + componentName: 'AppInitiatedActionPage', + kcAction: 'configure_totp' }, { path: 'security/device-activity', diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js b/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js index a0eb770186..61e5f9adc3 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js +++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js @@ -769,7 +769,7 @@ './icons/parachute-box-icon.js': '@empty', './icons/paragraph-icon.js': '@empty', './icons/parking-icon.js': '@empty', - './icons/passport-icon.js': '@empty', + //'./icons/passport-icon.js': '@empty', './icons/pastafarianism-icon.js': '@empty', './icons/paste-icon.js': '@empty', './icons/pause-icon.js': '@empty',