222 lines
6.7 KiB
JavaScript
222 lines
6.7 KiB
JavaScript
// Copyright 2020 Red Hat, Inc
|
|
//
|
|
// 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 React from 'react'
|
|
import PropTypes from 'prop-types'
|
|
import { connect } from 'react-redux'
|
|
|
|
import {
|
|
Accordion,
|
|
AccordionItem,
|
|
AccordionToggle,
|
|
AccordionContent,
|
|
Button,
|
|
ButtonVariant,
|
|
ClipboardCopy,
|
|
ClipboardCopyVariant,
|
|
Modal,
|
|
ModalVariant
|
|
} from '@patternfly/react-core'
|
|
import {
|
|
UserIcon,
|
|
SignInAltIcon,
|
|
SignOutAltIcon,
|
|
HatWizardIcon
|
|
} from '@patternfly/react-icons'
|
|
|
|
import * as moment from 'moment'
|
|
|
|
import { apiUrl } from '../../api'
|
|
import { fetchUserACL } from '../../actions/user'
|
|
import { withAuth } from 'oidc-react'
|
|
import { getHomepageUrl } from '../../api'
|
|
|
|
|
|
class AuthContainer extends React.Component {
|
|
static propTypes = {
|
|
user: PropTypes.object,
|
|
tenant: PropTypes.object,
|
|
dispatch: PropTypes.func.isRequired,
|
|
timezone: PropTypes.string.isRequired,
|
|
info: PropTypes.object,
|
|
auth: PropTypes.object,
|
|
// Props coming from withAuth
|
|
signIn: PropTypes.func,
|
|
signOut: PropTypes.func,
|
|
}
|
|
|
|
constructor(props) {
|
|
super(props)
|
|
this.state = {
|
|
isModalOpen: false,
|
|
showZuulClientConfig: false,
|
|
}
|
|
this.handleModalToggle = () => {
|
|
this.setState(({ isModalOpen }) => ({
|
|
isModalOpen: !isModalOpen
|
|
}))
|
|
}
|
|
this.handleConfigToggle = () => {
|
|
this.setState(({ showZuulClientConfig }) => ({
|
|
showZuulClientConfig: !showZuulClientConfig
|
|
}))
|
|
}
|
|
}
|
|
|
|
componentDidUpdate() {
|
|
const { user, tenant } = this.props
|
|
|
|
// Make sure the token is current and the tenant is up to date.
|
|
if (user.data && user.tenant !== tenant.name) {
|
|
console.log('Refreshing ACL', user.tenant, tenant.name)
|
|
this.props.dispatch(fetchUserACL(tenant.name, user))
|
|
}
|
|
}
|
|
|
|
ZuulClientConfig() {
|
|
const { user, tenant } = this.props
|
|
|
|
let ZCconfig
|
|
ZCconfig = '[' + tenant.name + ']\n'
|
|
ZCconfig = ZCconfig + 'url=' + apiUrl.slice(0, -4) + '\n'
|
|
ZCconfig = ZCconfig + 'tenant=' + tenant.name + '\n'
|
|
ZCconfig = ZCconfig + 'auth_token=' + user.token + '\n'
|
|
|
|
return ZCconfig
|
|
}
|
|
|
|
renderModal() {
|
|
const { user, tenant, timezone } = this.props
|
|
const { isModalOpen, showZuulClientConfig } = this.state
|
|
let config = this.ZuulClientConfig(tenant, user.data)
|
|
let valid_until = moment.unix(user.data.expires_at).tz(timezone).format('YYYY-MM-DD HH:mm:ss')
|
|
return (
|
|
<React.Fragment>
|
|
<Modal
|
|
variant={ModalVariant.small}
|
|
title="User Info"
|
|
isOpen={isModalOpen}
|
|
onClose={this.handleModalToggle}
|
|
actions={[
|
|
<Button
|
|
key="SignOut"
|
|
variant="primary"
|
|
onClick={() => {
|
|
this.props.signOut()
|
|
}}
|
|
title="Note that you will be logged out of Zuul, but not out of your identity provider.">
|
|
Sign Out
|
|
<SignOutAltIcon title='Sign Out' />
|
|
</Button>
|
|
]}
|
|
>
|
|
<div>
|
|
<p key="user">Name: <strong>{user.data.profile.name}</strong></p>
|
|
<p key="preferred_username">Logged in as: <strong>{user.data.profile.preferred_username}</strong>
|
|
{(user.isAdmin && user.scope.indexOf(tenant.name) !== -1) && (
|
|
<HatWizardIcon title='This user can perform admin tasks' />
|
|
)}</p>
|
|
<Accordion asDefinitionList>
|
|
<AccordionItem>
|
|
<AccordionToggle
|
|
onClick={this.handleConfigToggle}
|
|
isExpanded={showZuulClientConfig}
|
|
title='Configuration parameters that can be used to perform tasks with the CLI'
|
|
id="ZCConfig">
|
|
Show Zuul Client Config
|
|
</AccordionToggle>
|
|
<AccordionContent
|
|
isHidden={!showZuulClientConfig}>
|
|
<ClipboardCopy isCode isReadOnly variant={ClipboardCopyVariant.expansion}>{config}</ClipboardCopy>
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
</Accordion>
|
|
<p key="valid_until">Token expiry date: <strong>{valid_until}</strong></p>
|
|
<p key="footer">
|
|
Zuul stores and uses information such as your username
|
|
and your email to provide some features. This data is
|
|
stored <strong>in your browser only</strong> and is
|
|
discarded once you log out.
|
|
</p>
|
|
</div>
|
|
</Modal>
|
|
</React.Fragment>
|
|
)
|
|
}
|
|
|
|
renderButton(containerStyles) {
|
|
|
|
const { user } = this.props
|
|
if (!user.data) {
|
|
return (
|
|
<div style={containerStyles}>
|
|
<Button
|
|
key="SignIn"
|
|
variant={ButtonVariant.plain}
|
|
onClick={() => {
|
|
const redirect_target = window.location.href.slice(getHomepageUrl().length)
|
|
localStorage.setItem('zuul_auth_redirect', redirect_target)
|
|
this.props.signIn()
|
|
}}>
|
|
Sign in
|
|
<SignInAltIcon title='Sign In' />
|
|
</Button>
|
|
</div>
|
|
)
|
|
} else {
|
|
return (user.data.isFetching ? <div style={containerStyles}>Loading...</div> :
|
|
<div style={containerStyles}>
|
|
{this.renderModal()}
|
|
<Button
|
|
variant={ButtonVariant.plain}
|
|
key="userinfo"
|
|
onClick={this.handleModalToggle}>
|
|
<UserIcon title='User details' />
|
|
{user.data.profile.preferred_username}
|
|
</Button>
|
|
</div>
|
|
)
|
|
}
|
|
}
|
|
|
|
render() {
|
|
const { info, auth } = this.props
|
|
const textColor = '#d1d1d1'
|
|
const containerStyles = {
|
|
color: textColor,
|
|
border: 'solid #2b2b2b',
|
|
borderWidth: '0 0 0 1px',
|
|
display: 'initial',
|
|
padding: '6px'
|
|
}
|
|
|
|
if (info.isFetching) {
|
|
return (<><div style={containerStyles}>Fetching auth info ...</div></>)
|
|
}
|
|
if (auth.info) {
|
|
return this.renderButton(containerStyles)
|
|
} else {
|
|
return (<div style={containerStyles} title="Authentication disabled">-</div>)
|
|
}
|
|
}
|
|
}
|
|
|
|
export default connect(state => ({
|
|
auth: state.auth,
|
|
user: state.user,
|
|
tenant: state.tenant,
|
|
timezone: state.timezone,
|
|
info: state.info,
|
|
}))(withAuth(AuthContainer))
|