summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwouter-admiraal-sonarsource <45544358+wouter-admiraal-sonarsource@users.noreply.github.com>2018-12-10 08:47:36 +0100
committerSonarTech <sonartech@sonarsource.com>2018-12-10 20:21:00 +0100
commit36efcfabb50b8fd9086ec906d733a159a41e5367 (patch)
treeab8ca5a3bc80cd416af8123953165ab0b5a5e21d
parentaccbb5561aaad5814873806858258eb5fe89e270 (diff)
downloadsonarqube-36efcfabb50b8fd9086ec906d733a159a41e5367.tar.gz
sonarqube-36efcfabb50b8fd9086ec906d733a159a41e5367.zip
Hardening dec 5 (#1030)
* SONAR-11533 Drop obsolete bullet in 'How To Use' section for encryption * SONAR-11541 Give branch and PR names more room in dropdown * SONAR-11469 Display an Alert when redirected to login When a user is redirected to the login page after trying to access a page which she doesn't have sufficient permissions for, display an alert explaining why the user was redirected, and provide a link to go back to the homepage.
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css3
-rw-r--r--server/sonar-web/src/main/js/app/styles/init/misc.css18
-rw-r--r--server/sonar-web/src/main/js/apps/sessions/components/LoginSonarCloud.css13
-rw-r--r--server/sonar-web/src/main/js/apps/sessions/components/LoginSonarCloud.tsx99
-rw-r--r--server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginSonarCloud-test.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginSonarCloud-test.tsx.snap217
-rw-r--r--server/sonar-web/src/main/js/apps/settings/encryption/GenerateSecretKeyForm.tsx2
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties3
8 files changed, 262 insertions, 107 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css
index 50141bd6c0c..a9eaf7e918b 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css
+++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css
@@ -31,6 +31,7 @@
.navbar-context-branches .popup {
min-width: 430px;
+ max-width: 650px;
}
.navbar-context-meta-branch-menu-title {
@@ -44,7 +45,7 @@
}
.navbar-context-meta-branch-menu-item-name {
- flex: 0 1 300px; /* Workaround for SONAR-10971 */
+ flex: 0 1 550px; /* Workaround for SONAR-10971 */
min-width: 0;
}
diff --git a/server/sonar-web/src/main/js/app/styles/init/misc.css b/server/sonar-web/src/main/js/app/styles/init/misc.css
index e8cc9b5fa24..6c7364ab3ec 100644
--- a/server/sonar-web/src/main/js/app/styles/init/misc.css
+++ b/server/sonar-web/src/main/js/app/styles/init/misc.css
@@ -372,6 +372,24 @@ td.big-spacer-top {
color: rgba(68, 68, 68, 0.3);
}
+.horizontal-pipe-separator {
+ display: flex;
+ align-items: center;
+ margin-top: calc(4 * var(--gridSize));
+ margin-bottom: calc(4 * var(--gridSize));
+}
+
+.horizontal-pipe-separator > .horizontal-separator {
+ margin: 0 4px;
+}
+
+.horizontal-separator {
+ min-width: 16px;
+ height: 1px;
+ flex-grow: 1;
+ background-color: var(--barBorderColor);
+}
+
.vertical-separator {
width: 1px;
min-height: 16px;
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginSonarCloud.css b/server/sonar-web/src/main/js/apps/sessions/components/LoginSonarCloud.css
index 5f724dfc73d..aace3eb01ed 100644
--- a/server/sonar-web/src/main/js/apps/sessions/components/LoginSonarCloud.css
+++ b/server/sonar-web/src/main/js/apps/sessions/components/LoginSonarCloud.css
@@ -17,6 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+.sonarcloud-login-alert {
+ margin: 10vh auto 5vh auto;
+ width: 256px;
+}
+
.sonarcloud-login-page {
margin-top: 15vh;
width: 216px;
@@ -25,6 +30,10 @@
padding: calc(4 * var(--gridSize)) 20px;
}
+.sonarcloud-login-alert ~ .sonarcloud-login-page {
+ margin-top: 0;
+}
+
.sonarcloud-login-page-large {
width: 300px;
}
@@ -48,3 +57,7 @@
.sonarcloud-oauth-providers.oauth-providers .oauth-providers-help {
right: -22px;
}
+
+.sonarcloud-login-cancel {
+ text-align: center;
+}
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginSonarCloud.tsx b/server/sonar-web/src/main/js/apps/sessions/components/LoginSonarCloud.tsx
index ce758229acc..2f40d8724ab 100644
--- a/server/sonar-web/src/main/js/apps/sessions/components/LoginSonarCloud.tsx
+++ b/server/sonar-web/src/main/js/apps/sessions/components/LoginSonarCloud.tsx
@@ -18,59 +18,92 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { connect } from 'react-redux';
import * as classNames from 'classnames';
import LoginForm from './LoginForm';
import OAuthProviders from './OAuthProviders';
import { getBaseUrl } from '../../../helpers/urls';
import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { Alert } from '../../../components/ui/Alert';
import './LoginSonarCloud.css';
+import { Store } from '../../../store/rootReducer';
interface Props {
identityProviders: T.IdentityProvider[];
onSubmit: (login: string, password: string) => Promise<void>;
returnTo: string;
showForm?: boolean;
+ authorizationError?: boolean;
+ authenticationError?: boolean;
}
-export default function LoginSonarCloud({
+function formatLabel(name: string) {
+ return translateWithParameters('login.with_x', name);
+}
+
+export function LoginSonarCloud({
+ showForm,
identityProviders,
- onSubmit,
returnTo,
- showForm
+ onSubmit,
+ authorizationError,
+ authenticationError
}: Props) {
const displayForm = showForm || identityProviders.length <= 0;
+ const displayErrorAction = authorizationError || authenticationError;
return (
- <div
- className={classNames('sonarcloud-login-page boxed-group boxed-group-inner', {
- 'sonarcloud-login-page-large': displayForm
- })}
- id="login_form">
- <div className="text-center">
- <img
- alt="SonarCloud logo"
- height={36}
- src={`${getBaseUrl()}/images/sonarcloud-square-logo.svg`}
- width={36}
- />
- <h1 className="sonarcloud-login-title">
- {translate('login.login_or_signup_to_sonarcloud')}
- </h1>
- </div>
-
- {displayForm ? (
- <LoginForm onSubmit={onSubmit} returnTo={returnTo} />
- ) : (
- <OAuthProviders
- className="sonarcloud-oauth-providers"
- formatLabel={formatLabel}
- identityProviders={identityProviders}
- returnTo={returnTo}
- />
+ <>
+ {displayErrorAction && (
+ <Alert className="sonarcloud-login-alert" display="block" variant="warning">
+ {translate('login.unauthorized_access_alert')}
+ </Alert>
)}
- </div>
+ <div
+ className={classNames('sonarcloud-login-page boxed-group boxed-group-inner', {
+ 'sonarcloud-login-page-large': displayForm
+ })}
+ id="login_form">
+ <div className="text-center">
+ <img
+ alt="SonarCloud logo"
+ height={36}
+ src={`${getBaseUrl()}/images/sonarcloud-square-logo.svg`}
+ width={36}
+ />
+ <h1 className="sonarcloud-login-title">
+ {translate('login.login_or_signup_to_sonarcloud')}
+ </h1>
+ </div>
+
+ {displayForm ? (
+ <LoginForm onSubmit={onSubmit} returnTo={returnTo} />
+ ) : (
+ <OAuthProviders
+ className="sonarcloud-oauth-providers"
+ formatLabel={formatLabel}
+ identityProviders={identityProviders}
+ returnTo={returnTo}
+ />
+ )}
+
+ {displayErrorAction && (
+ <div className="sonarcloud-login-cancel">
+ <div className="horizontal-pipe-separator">
+ <div className="horizontal-separator" />
+ <span className="note">{translate('or')}</span>
+ <div className="horizontal-separator" />
+ </div>
+ <a href={`${getBaseUrl()}/`}>{translate('go_back_to_homepage')}</a>
+ </div>
+ )}
+ </div>
+ </>
);
}
-function formatLabel(name: string) {
- return translateWithParameters('login.with_x', name);
-}
+const mapStateToProps = (state: Store) => ({
+ authorizationError: state.appState.authorizationError,
+ authenticationError: state.appState.authenticationError
+});
+
+export default connect(mapStateToProps)(LoginSonarCloud);
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginSonarCloud-test.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginSonarCloud-test.tsx
index f29a3d8b963..b2a00661ed4 100644
--- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginSonarCloud-test.tsx
+++ b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginSonarCloud-test.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import LoginSonarCloud from '../LoginSonarCloud';
+import { LoginSonarCloud } from '../LoginSonarCloud';
const identityProvider = {
backgroundColor: '#000',
@@ -50,3 +50,15 @@ it('logs in with simple form', () => {
shallow(<LoginSonarCloud identityProviders={[]} onSubmit={jest.fn()} returnTo="" />)
).toMatchSnapshot();
});
+
+it("shows an warning message if there's an authorization error", () => {
+ const wrapper = shallow(
+ <LoginSonarCloud
+ authorizationError={true}
+ identityProviders={[identityProvider]}
+ onSubmit={jest.fn()}
+ returnTo=""
+ />
+ );
+ expect(wrapper).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginSonarCloud-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginSonarCloud-test.tsx.snap
index cd3b0f00ea8..56308c07525 100644
--- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginSonarCloud-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginSonarCloud-test.tsx.snap
@@ -1,93 +1,170 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`logs in with identity provider 1`] = `
-<div
- className="sonarcloud-login-page boxed-group boxed-group-inner"
- id="login_form"
->
+<Fragment>
<div
- className="text-center"
+ className="sonarcloud-login-page boxed-group boxed-group-inner"
+ id="login_form"
>
- <img
- alt="SonarCloud logo"
- height={36}
- src="/images/sonarcloud-square-logo.svg"
- width={36}
- />
- <h1
- className="sonarcloud-login-title"
+ <div
+ className="text-center"
>
- login.login_or_signup_to_sonarcloud
- </h1>
+ <img
+ alt="SonarCloud logo"
+ height={36}
+ src="/images/sonarcloud-square-logo.svg"
+ width={36}
+ />
+ <h1
+ className="sonarcloud-login-title"
+ >
+ login.login_or_signup_to_sonarcloud
+ </h1>
+ </div>
+ <OAuthProviders
+ className="sonarcloud-oauth-providers"
+ formatLabel={[Function]}
+ identityProviders={
+ Array [
+ Object {
+ "backgroundColor": "#000",
+ "iconPath": "/some/path",
+ "key": "foo",
+ "name": "foo",
+ },
+ ]
+ }
+ returnTo=""
+ />
</div>
- <OAuthProviders
- className="sonarcloud-oauth-providers"
- formatLabel={[Function]}
- identityProviders={
- Array [
- Object {
- "backgroundColor": "#000",
- "iconPath": "/some/path",
- "key": "foo",
- "name": "foo",
- },
- ]
- }
- returnTo=""
- />
-</div>
+</Fragment>
`;
exports[`logs in with simple form 1`] = `
-<div
- className="sonarcloud-login-page boxed-group boxed-group-inner sonarcloud-login-page-large"
- id="login_form"
->
+<Fragment>
<div
- className="text-center"
+ className="sonarcloud-login-page boxed-group boxed-group-inner sonarcloud-login-page-large"
+ id="login_form"
>
- <img
- alt="SonarCloud logo"
- height={36}
- src="/images/sonarcloud-square-logo.svg"
- width={36}
- />
- <h1
- className="sonarcloud-login-title"
+ <div
+ className="text-center"
>
- login.login_or_signup_to_sonarcloud
- </h1>
+ <img
+ alt="SonarCloud logo"
+ height={36}
+ src="/images/sonarcloud-square-logo.svg"
+ width={36}
+ />
+ <h1
+ className="sonarcloud-login-title"
+ >
+ login.login_or_signup_to_sonarcloud
+ </h1>
+ </div>
+ <LoginForm
+ onSubmit={[MockFunction]}
+ returnTo=""
+ />
</div>
- <LoginForm
- onSubmit={[MockFunction]}
- returnTo=""
- />
-</div>
+</Fragment>
`;
exports[`logs in with simple form 2`] = `
-<div
- className="sonarcloud-login-page boxed-group boxed-group-inner sonarcloud-login-page-large"
- id="login_form"
->
+<Fragment>
<div
- className="text-center"
+ className="sonarcloud-login-page boxed-group boxed-group-inner sonarcloud-login-page-large"
+ id="login_form"
>
- <img
- alt="SonarCloud logo"
- height={36}
- src="/images/sonarcloud-square-logo.svg"
- width={36}
+ <div
+ className="text-center"
+ >
+ <img
+ alt="SonarCloud logo"
+ height={36}
+ src="/images/sonarcloud-square-logo.svg"
+ width={36}
+ />
+ <h1
+ className="sonarcloud-login-title"
+ >
+ login.login_or_signup_to_sonarcloud
+ </h1>
+ </div>
+ <LoginForm
+ onSubmit={[MockFunction]}
+ returnTo=""
+ />
+ </div>
+</Fragment>
+`;
+
+exports[`shows an warning message if there's an authorization error 1`] = `
+<Fragment>
+ <Alert
+ className="sonarcloud-login-alert"
+ display="block"
+ variant="warning"
+ >
+ login.unauthorized_access_alert
+ </Alert>
+ <div
+ className="sonarcloud-login-page boxed-group boxed-group-inner"
+ id="login_form"
+ >
+ <div
+ className="text-center"
+ >
+ <img
+ alt="SonarCloud logo"
+ height={36}
+ src="/images/sonarcloud-square-logo.svg"
+ width={36}
+ />
+ <h1
+ className="sonarcloud-login-title"
+ >
+ login.login_or_signup_to_sonarcloud
+ </h1>
+ </div>
+ <OAuthProviders
+ className="sonarcloud-oauth-providers"
+ formatLabel={[Function]}
+ identityProviders={
+ Array [
+ Object {
+ "backgroundColor": "#000",
+ "iconPath": "/some/path",
+ "key": "foo",
+ "name": "foo",
+ },
+ ]
+ }
+ returnTo=""
/>
- <h1
- className="sonarcloud-login-title"
+ <div
+ className="sonarcloud-login-cancel"
>
- login.login_or_signup_to_sonarcloud
- </h1>
+ <div
+ className="horizontal-pipe-separator"
+ >
+ <div
+ className="horizontal-separator"
+ />
+ <span
+ className="note"
+ >
+ or
+ </span>
+ <div
+ className="horizontal-separator"
+ />
+ </div>
+ <a
+ href="/"
+ >
+ go_back_to_homepage
+ </a>
+ </div>
</div>
- <LoginForm
- onSubmit={[MockFunction]}
- returnTo=""
- />
-</div>
+</Fragment>
`;
diff --git a/server/sonar-web/src/main/js/apps/settings/encryption/GenerateSecretKeyForm.tsx b/server/sonar-web/src/main/js/apps/settings/encryption/GenerateSecretKeyForm.tsx
index 1855fe22d32..7f1136ada2f 100644
--- a/server/sonar-web/src/main/js/apps/settings/encryption/GenerateSecretKeyForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/encryption/GenerateSecretKeyForm.tsx
@@ -85,7 +85,7 @@ export default class GenerateSecretKeyForm extends React.PureComponent<Props, St
<form id="generate-secret-key-form" onSubmit={this.handleSubmit}>
<p className="spacer-bottom">
<FormattedMessage
- defaultMessage={translate('encryptionFormattedMessage.secret_key_description')}
+ defaultMessage={translate('encryption.secret_key_description')}
id="encryption.secret_key_description"
values={{
moreInformationLink: (
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index da207482207..f719e11c23b 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -1461,6 +1461,7 @@ login.login_to_sonarqube=Log In to SonarQube
login.login_or_signup_to_sonarcloud=Log in or Sign up to SonarCloud
login.login_with_x=Log in with {0}
login.more_options=More options
+login.unauthorized_access_alert=You are not authorized to access this page. Please log in with more privileges and try again.
login.with_x=With {0}
unauthorized.message=You're not authorized to access this page. Please contact the administrator.
@@ -2970,7 +2971,7 @@ encryption.encrypt=Encrypt
encryption.secret_key_description=Secret key is required to be able to encrypt properties. {moreInformationLink}
encryption.secret_key=Secret Key
encryption.how_to_use=How To Use
-encryption.how_to_use.content=<ul><li>Store the secret key in the file <code>~/.sonar/sonar-secret.txt</code> of the server. This file can be relocated by defining the property <code>sonar.secretKeyPath</code> in <code>conf/sonar.properties</code></li><li>Restrict access to this file by making it readable and by owner only</li><li>Restart the server if the property <code>sonar.secretKeyPath</code> has been set or changed.</li><li>Copy this file on all the machines that execute code inspection. Define the property <code>sonar.secretKeyPath</code> on those machines if the path is not <code>~/.sonar/sonar-secret.txt</code>.</li><li>For each property that you want to encrypt, generate the encrypted value and replace the original value wherever it is stored (configuration files, command lines).</li></ul>
+encryption.how_to_use.content=<ul><li>Store the secret key in the file <code>~/.sonar/sonar-secret.txt</code> of the server. This file can be relocated by defining the property <code>sonar.secretKeyPath</code> in <code>conf/sonar.properties</code></li><li>Restrict access to this file by making it readable and by owner only</li><li>Restart the server if the property <code>sonar.secretKeyPath</code> has been set or changed.</li><li>For each property that you want to encrypt, generate the encrypted value and replace the original value wherever it is stored (configuration files, command lines).</li></ul>
#------------------------------------------------------------------------------