passbolt-styleguide
Version:
Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.
371 lines (357 loc) • 14.3 kB
JavaScript
/**
* Passbolt ~ Open source password manager for teams
* Copyright (c) 2022 Passbolt SA (https://www.passbolt.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) 2022 Passbolt SA (https://www.passbolt.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.passbolt.com Passbolt(tm)
* @since 3.9.0
*/
import React from "react";
import PropTypes from "prop-types";
import { withActionFeedback } from "../../../contexts/ActionFeedbackContext";
import { withAdministrationWorkspace } from "../../../contexts/AdministrationWorkspaceContext";
import { Trans, withTranslation } from "react-i18next";
import Select from "../../Common/Select/Select";
import DisplayAdministrationSsoActions from "../DisplayAdministrationWorkspaceActions/DisplayAdministrationSsoActions/DisplayAdministrationSsoActions";
import { withAdminSso } from "../../../contexts/AdminSsoContext";
import SsoProviders from "./SsoProviders.data";
import { withAppContext } from "../../../../shared/context/AppContext/AppContext";
import AzureSsoProviderForm from "./SsoProviderForm/AzureSsoProviderForm";
import GoogleSsoProviderForm from "./SsoProviderForm/GoogleSsoProviderForm";
import OAuth2SsoProviderForm from "./SsoProviderForm/OAuth2SsoProviderForm";
import AdfsSsoProviderForm from "./SsoProviderForm/AdfsSsoProviderForm";
import AzureSsoSettingsEntity from "../../../../shared/models/entity/ssoSettings/AzureSsoSettingsEntity";
import GoogleSsoSettingsEntity from "../../../../shared/models/entity/ssoSettings/GoogleSsoSettingsEntity";
import OAuth2SsoSettingsEntity from "../../../../shared/models/entity/ssoSettings/OAuth2SsoSettingsEntity";
import AdfsSsoSettingsEntity from "../../../../shared/models/entity/ssoSettings/AdfsSsoSettingsEntity";
import { createSafePortal } from "../../../../shared/utils/portals";
import FileTextSVG from "../../../../img/svg/file_text.svg";
import GoSVG from "../../../../img/svg/go.svg";
import PingOneSsoSettingsEntity from "../../../../shared/models/entity/ssoSettings/PingOneSsoSettingsEntity";
import PingOneSsoProviderForm from "./SsoProviderForm/PingOneSsoProviderForm";
/**
* This component displays the SSO administration settings
*/
class ManageSsoSettings extends React.Component {
/**
* Constructor
* @param {Object} props
*/
constructor(props) {
super(props);
this.state = this.defaultState;
this.bindCallbacks();
}
/**
* Get default state
* @returns {*}
*/
get defaultState() {
return {
loading: true,
providers: [],
};
}
async componentDidMount() {
const ssoConfig = await this.props.adminSsoContext.loadSsoConfiguration();
this.setState({
loading: false,
providers: ssoConfig?.providers || [],
});
}
/**
* Bind callbacks methods
*/
bindCallbacks() {
this.handleProviderInputChange = this.handleProviderInputChange.bind(this);
this.handleSsoSettingToggle = this.handleSsoSettingToggle.bind(this);
}
/**
* Handle provider input change.
*/
handleProviderInputChange(event) {
this.props.adminSsoContext.changeProvider({
id: event.target.value,
});
}
/**
* Handle the SSO settings toggle
*/
handleSsoSettingToggle() {
const isToggleEnabled = this.props.adminSsoContext.isSsoConfigActivated();
if (isToggleEnabled) {
this.props.adminSsoContext.disableSso();
}
}
/**
* Should input be disabled? True if state is loading or processing
* @returns {boolean}
*/
hasAllInputDisabled() {
return this.props.adminSsoContext.isProcessing() || this.state.loading;
}
/**
* Get all the SSO providers the browser extension knows.
* Also, sets the `disabled` flag to the provider that are not known/activated on the API.
* @returns {Array<object>}
*/
get allSsoProviders() {
const apiSupportedProvider = this.state.providers;
return (
SsoProviders.map((bextKnownProvider) => {
const newProvider = { ...bextKnownProvider };
newProvider.disabled = Boolean(newProvider.disabled) || !apiSupportedProvider.includes(newProvider.id);
return newProvider;
})
// make sure to hide the providers we want to hide if their are not available on the API
.filter((provider) => !provider.disabled || (provider.disabled && !provider?.hiddenIfDisabled))
);
}
/**
* Get the supported SSO providers.
* @returns {Array<{value: string, label: string}}
*/
get supportedSsoProviders() {
const providerIdList = this.state.providers;
/*
* providers must be known on both side (API / Bext) in order to work.
* Obviously, the API can't work with an unknown provider.
* On Bext side, we can't provide a third-party SSO provider specific form if it's is unknown
*/
const providerDataList = [];
providerIdList.forEach((providerId) => {
const providerData = SsoProviders.find((provider) => provider.id === providerId);
if (providerData && !providerData.disabled) {
providerDataList.push({
value: providerData.id,
label: providerData.name,
});
}
});
return providerDataList;
}
/**
* Returns true if the data is loaded.
* Useful to avoid UI blinking during data loading.
* @returns {boolean}
*/
isReady() {
return this.props.adminSsoContext.isDataReady();
}
/**
* Render the component
* @returns {JSX}
*/
render() {
const ssoContext = this.props.adminSsoContext;
const ssoConfig = ssoContext.getSsoConfiguration();
const isSsoActivated = ssoContext.isSsoConfigActivated();
return (
<div className="row">
<div className="third-party-provider-settings sso-settings main-column">
<div className="main-content">
<h3 className="title">
<span className="input toggle-switch form-element">
<input
type="checkbox"
className="toggle-switch-checkbox checkbox"
name="ssoToggle"
onChange={this.handleSsoSettingToggle}
checked={isSsoActivated}
disabled={this.hasAllInputDisabled()}
id="ssoToggle"
/>
<label htmlFor="ssoToggle">
<Trans>Single Sign-On</Trans>
</label>
</span>
</h3>
{this.isReady() && !isSsoActivated && (
<>
<h4 className="no-border">
<Trans>Select a provider</Trans>
</h4>
<div className="provider-list">
{this.allSsoProviders.map((provider) => (
<div
key={provider.id}
className={`provider button ${provider.disabled ? "disabled" : ""}`}
id={provider.id}
onClick={() => this.props.adminSsoContext.changeProvider(provider)}
>
<div className="provider-logo">{provider.icon}</div>
<p className="provider-name">
{provider.name}
<br />
{provider.disabled && <Trans>(not yet available)</Trans>}
</p>
</div>
))}
</div>
</>
)}
{this.isReady() && isSsoActivated && (
<form className="form">
<div className="select-wrapper input">
<label htmlFor="sso-provider-input">
<Trans>Single Sign-On provider</Trans>
</label>
<Select
id="sso-provider-input"
name="provider"
items={this.supportedSsoProviders}
value={ssoConfig?.provider}
onChange={this.handleProviderInputChange}
/>
</div>
{ssoConfig?.provider === AzureSsoSettingsEntity.PROVIDER_ID && <AzureSsoProviderForm />}
{ssoConfig?.provider === GoogleSsoSettingsEntity.PROVIDER_ID && <GoogleSsoProviderForm />}
{ssoConfig?.provider === OAuth2SsoSettingsEntity.PROVIDER_ID && <OAuth2SsoProviderForm />}
{ssoConfig?.provider === AdfsSsoSettingsEntity.PROVIDER_ID && <AdfsSsoProviderForm />}
{ssoConfig?.provider === PingOneSsoSettingsEntity.PROVIDER_ID && <PingOneSsoProviderForm />}
</form>
)}
</div>
{this.props.adminSsoContext.hasFormChanged() && (
<div className="warning message" id="sso-setting-overridden-banner">
<div>
<p>
<Trans>Don't forget to save your settings to apply your modification.</Trans>
</p>
</div>
</div>
)}
</div>
<DisplayAdministrationSsoActions />
{createSafePortal(
<>
<div className="sidebar-help-section warning message" id="sso-setting-security-warning-banner">
<h3>
<Trans>Important notice:</Trans>
</h3>
<p>
<Trans>Enabling SSO changes the security risks.</Trans>{" "}
<Trans>
For example an attacker with a local machine access maybe be able to access secrets, if the user is
still logged in with the Identity provider.
</Trans>{" "}
<Trans>Make sure users follow screen lock best practices.</Trans>
<a href="https://passbolt.com/docs/admin/authentication/sso/" target="_blank" rel="noopener noreferrer">
<Trans>Learn more</Trans>
</a>
</p>
</div>
<div className="sidebar-help-section">
<h3>
<Trans>Need some help?</Trans>
</h3>
<p>
<Trans>For more information about SSO, checkout the dedicated page on the help website.</Trans>
</p>
<a
className="button"
href="https://passbolt.com/docs/admin/authentication/sso/"
target="_blank"
rel="noopener noreferrer"
>
<FileTextSVG />
<span>
<Trans>Read the documentation</Trans>
</span>
</a>
</div>
{ssoConfig?.provider === AzureSsoSettingsEntity.PROVIDER_ID && (
<div className="sidebar-help-section">
<h3>
<Trans>How do I configure a AzureAD SSO?</Trans>
</h3>
<a
className="button"
href="https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/add-application-portal-setup-sso"
target="_blank"
rel="noopener noreferrer"
>
<GoSVG />
<span>
<Trans>Read the documentation</Trans>
</span>
</a>
</div>
)}
{ssoConfig?.provider === GoogleSsoSettingsEntity.PROVIDER_ID && (
<div className="sidebar-help-section">
<h3>
<Trans>How do I configure a Google SSO?</Trans>
</h3>
<a
className="button"
href="https://developers.google.com/identity/openid-connect/openid-connect"
target="_blank"
rel="noopener noreferrer"
>
<GoSVG />
<span>
<Trans>Read the documentation</Trans>
</span>
</a>
</div>
)}
{ssoConfig?.provider === AdfsSsoSettingsEntity.PROVIDER_ID && (
<div className="sidebar-help-section">
<h3>
<Trans>How do I configure an AD FS SSO?</Trans>
</h3>
<a
className="button"
href="https://learn.microsoft.com/en-gb/microsoft-365/troubleshoot/active-directory/set-up-adfs-for-single-sign-on"
target="_blank"
rel="noopener noreferrer"
>
<GoSVG />
<span>
<Trans>Read the documentation</Trans>
</span>
</a>
</div>
)}
{ssoConfig?.provider === PingOneSsoSettingsEntity.PROVIDER_ID && (
<div className="sidebar-help-section">
<h3>
<Trans>How do I configure PingOne SSO?</Trans>
</h3>
<a
className="button"
href="https://docs.pingidentity.com/pingone/applications/p1_applications_add_applications.html"
target="_blank"
rel="noopener noreferrer"
>
<GoSVG />
<span>
<Trans>Read the documentation</Trans>
</span>
</a>
</div>
)}
</>,
document.getElementById("administration-help-panel"),
)}
</div>
);
}
}
ManageSsoSettings.propTypes = {
administrationWorkspaceContext: PropTypes.object, // The administration workspace context
adminSsoContext: PropTypes.object, // The administration sso configuration context
actionFeedbackContext: PropTypes.any, // The action feedback context
context: PropTypes.any, // The application context
t: PropTypes.func, // The translation function
};
export default withAppContext(
withActionFeedback(withAdministrationWorkspace(withAdminSso(withTranslation("common")(ManageSsoSettings)))),
);