diff options
15 files changed, 181 insertions, 101 deletions
diff --git a/it/it-plugins/base-auth-plugin/src/main/java/FakeBaseIdProvider.java b/it/it-plugins/base-auth-plugin/src/main/java/FakeBaseIdProvider.java index 730bef971e1..a7d897b137f 100644 --- a/it/it-plugins/base-auth-plugin/src/main/java/FakeBaseIdProvider.java +++ b/it/it-plugins/base-auth-plugin/src/main/java/FakeBaseIdProvider.java @@ -21,6 +21,7 @@ import java.io.IOException; import org.sonar.api.config.Settings; import org.sonar.api.server.authentication.BaseIdentityProvider; import org.sonar.api.server.authentication.Display; +import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.server.authentication.UserIdentity; public class FakeBaseIdProvider implements BaseIdentityProvider { @@ -29,6 +30,8 @@ public class FakeBaseIdProvider implements BaseIdentityProvider { private static final String ALLOWS_USERS_TO_SIGN_UP = "sonar.auth.fake-base-id-provider.allowsUsersToSignUp"; private static final String USER_INFO = "sonar.auth.fake-base-id-provider.user"; + private static final String THROW_UNAUTHORIZED_EXCEPTION = "sonar.auth.fake-base-id-provider.throwUnauthorizedMessage"; + private final Settings settings; public FakeBaseIdProvider(Settings settings) { @@ -41,6 +44,11 @@ public class FakeBaseIdProvider implements BaseIdentityProvider { if (userInfoProperty == null) { throw new IllegalStateException(String.format("The property %s is required", USER_INFO)); } + boolean throwUnauthorizedException = settings.getBoolean(THROW_UNAUTHORIZED_EXCEPTION); + if (throwUnauthorizedException) { + throw new UnauthorizedException("A functional error has happened"); + } + String[] userInfos = userInfoProperty.split(","); context.authenticate(UserIdentity.builder() .setLogin(userInfos[0]) diff --git a/it/it-tests/src/test/java/it/user/BaseIdentityProviderTest.java b/it/it-tests/src/test/java/it/user/BaseIdentityProviderTest.java index 242d78caf7d..eda3d581f12 100644 --- a/it/it-tests/src/test/java/it/user/BaseIdentityProviderTest.java +++ b/it/it-tests/src/test/java/it/user/BaseIdentityProviderTest.java @@ -23,10 +23,11 @@ import com.google.common.base.Optional; import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.selenium.Selenese; import it.Category4Suite; +import java.io.File; +import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.sonarqube.ws.client.GetRequest; @@ -119,7 +120,6 @@ public class BaseIdentityProviderTest { } @Test - @Ignore("Do not understand why it's failing...") public void fail_to_authenticate_when_not_allowed_to_sign_up() throws Exception { enablePlugin(); setUserCreatedByAuthPlugin(USER_LOGIN, USER_PROVIDER_ID, USER_NAME, USER_EMAIL); @@ -182,6 +182,23 @@ public class BaseIdentityProviderTest { // TODO Add Selenium test to check login form } + @Test + public void display_message_in_ui_but_not_in_log_when_unauthorized_exception() throws Exception { + enablePlugin(); + setUserCreatedByAuthPlugin(USER_LOGIN, USER_PROVIDER_ID, USER_NAME, USER_EMAIL); + setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.throwUnauthorizedMessage", "true"); + + ORCHESTRATOR.executeSelenese(Selenese.builder().setHtmlTestsInClasspath("fail_to_authenticate_when_not_allowed_to_sign_up", + "/user/BaseIdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html" + ).build()); + + File logFile = ORCHESTRATOR.getServer().getLogs(); + assertThat(FileUtils.readFileToString(logFile)).doesNotContain("A functional error has happened"); + assertThat(FileUtils.readFileToString(logFile)).doesNotContain("UnauthorizedException"); + + userRule.verifyUserDoesNotExist(USER_LOGIN); + } + private static void setUserCreatedByAuthPlugin(String login, String providerId, String name, String email) { setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.user", login + "," + providerId + "," + name + "," + email); } diff --git a/it/it-tests/src/test/resources/user/BaseIdentityProviderTest/diplay_message_in_ui_but_not_in_log_when_unauthorized_exception.html b/it/it-tests/src/test/resources/user/BaseIdentityProviderTest/diplay_message_in_ui_but_not_in_log_when_unauthorized_exception.html new file mode 100644 index 00000000000..4d06368ae6c --- /dev/null +++ b/it/it-tests/src/test/resources/user/BaseIdentityProviderTest/diplay_message_in_ui_but_not_in_log_when_unauthorized_exception.html @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> + <title>fail_to_authenticate_when_not_allowed_to_sign_up</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> + <thead> + <tr> + <td rowspan="1" colspan="3">french</td> + </tr> + </thead> + <tbody> + <tr> + <td>open</td> + <td>/sessions/init/fake-base-id-provider</td> + <td></td> + </tr> + <tr> + <td>waitForText</td> + <td>bd</td> + <td>*You're not authorized to access this page. Please contact the administrator.*Reason : A functional error has happened*</td> + </tr> + </tbody> +</table> +</body> +</html> diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationError.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationError.java index c6628cdb055..5376261766c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationError.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationError.java @@ -21,19 +21,17 @@ package org.sonar.server.authentication; import java.io.IOException; import javax.servlet.http.HttpServletResponse; +import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import static java.lang.String.format; -import static org.sonar.server.authentication.EmailAlreadyExistsException.EMAIL_ALREADY_EXISTS_PATH; -import static org.sonar.server.authentication.NotAllowUserToSignUpException.NOT_ALLOWED_TO_SIGHNUP_PATH; +import static org.sonar.api.server.authentication.UnauthorizedException.UNAUTHORIZED_PATH; public class AuthenticationError { private static final Logger LOGGER = Loggers.get(AuthenticationError.class); - private static final String UNAUTHORIZED_PATH = "/sessions/unauthorized"; - private AuthenticationError() { // Utility class } @@ -48,12 +46,8 @@ public class AuthenticationError { redirectToUnauthorized(response); } - public static void handleNotAllowedToSignUpError(NotAllowUserToSignUpException e, HttpServletResponse response) { - redirectTo(response, format(NOT_ALLOWED_TO_SIGHNUP_PATH, e.getProvider().getName())); - } - - public static void handleEmailAlreadyExistsError(EmailAlreadyExistsException e, HttpServletResponse response) { - redirectTo(response, format(EMAIL_ALREADY_EXISTS_PATH, e.getEmail())); + public static void handleUnauthorizedError(UnauthorizedException e, HttpServletResponse response) { + redirectTo(response, e.getPath()); } private static void redirectToUnauthorized(HttpServletResponse response) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/InitFilter.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/InitFilter.java index 5111f8d3822..dd09ebe9d7b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/InitFilter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/InitFilter.java @@ -30,13 +30,13 @@ import javax.servlet.http.HttpServletResponse; import org.sonar.api.server.authentication.BaseIdentityProvider; import org.sonar.api.server.authentication.IdentityProvider; import org.sonar.api.server.authentication.OAuth2IdentityProvider; +import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.web.ServletFilter; import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; -import static org.sonar.server.authentication.AuthenticationError.handleEmailAlreadyExistsError; import static org.sonar.server.authentication.AuthenticationError.handleError; -import static org.sonar.server.authentication.AuthenticationError.handleNotAllowedToSignUpError; +import static org.sonar.server.authentication.AuthenticationError.handleUnauthorizedError; public class InitFilter extends ServletFilter { @@ -77,12 +77,10 @@ public class InitFilter extends ServletFilter { } else { throw new UnsupportedOperationException(format("Unsupported IdentityProvider class: %s ", provider.getClass())); } - } catch (NotAllowUserToSignUpException e) { - handleNotAllowedToSignUpError(e, (HttpServletResponse) response); - } catch (EmailAlreadyExistsException e) { - handleEmailAlreadyExistsError(e, (HttpServletResponse) response); + } catch (UnauthorizedException e) { + handleUnauthorizedError(e, (HttpServletResponse) response); } catch (Exception e) { - handleError(e, (HttpServletResponse) response, String.format("Fail to initialize authentication with provider '%s'", keyProvider)); + handleError(e, (HttpServletResponse) response, format("Fail to initialize authentication with provider '%s'", keyProvider)); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java index 919a4302d76..4701be2bc5a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java @@ -29,11 +29,12 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.sonar.api.server.authentication.IdentityProvider; import org.sonar.api.server.authentication.OAuth2IdentityProvider; +import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.web.ServletFilter; -import static org.sonar.server.authentication.AuthenticationError.handleEmailAlreadyExistsError; +import static java.lang.String.format; import static org.sonar.server.authentication.AuthenticationError.handleError; -import static org.sonar.server.authentication.AuthenticationError.handleNotAllowedToSignUpError; +import static org.sonar.server.authentication.AuthenticationError.handleUnauthorizedError; public class OAuth2CallbackFilter extends ServletFilter { @@ -64,14 +65,12 @@ public class OAuth2CallbackFilter extends ServletFilter { OAuth2IdentityProvider oauthProvider = (OAuth2IdentityProvider) provider; oauthProvider.callback(oAuth2ContextFactory.newCallback(httpRequest, (HttpServletResponse) response, oauthProvider)); } else { - handleError((HttpServletResponse) response, String.format("Not an OAuth2IdentityProvider: %s", provider.getClass())); + handleError((HttpServletResponse) response, format("Not an OAuth2IdentityProvider: %s", provider.getClass())); } - } catch (NotAllowUserToSignUpException e) { - handleNotAllowedToSignUpError(e, (HttpServletResponse) response); - } catch (EmailAlreadyExistsException e) { - handleEmailAlreadyExistsError(e, (HttpServletResponse) response); + } catch (UnauthorizedException e) { + handleUnauthorizedError(e, (HttpServletResponse) response); } catch (Exception e) { - handleError(e, (HttpServletResponse) response, String.format("Fail to callback authentication with %s", keyProvider)); + handleError(e, (HttpServletResponse) response, format("Fail to callback authentication with %s", keyProvider)); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/UserIdentityAuthenticator.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/UserIdentityAuthenticator.java index 9c3f11427e4..643daf69091 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/UserIdentityAuthenticator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/UserIdentityAuthenticator.java @@ -21,6 +21,7 @@ package org.sonar.server.authentication; import javax.servlet.http.HttpSession; import org.sonar.api.server.authentication.IdentityProvider; +import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.server.authentication.UserIdentity; import org.sonar.db.DbClient; import org.sonar.db.DbSession; @@ -30,6 +31,8 @@ import org.sonar.server.user.NewUser; import org.sonar.server.user.UpdateUser; import org.sonar.server.user.UserUpdater; +import static java.lang.String.format; + public class UserIdentityAuthenticator { private final DbClient dbClient; @@ -62,12 +65,13 @@ public class UserIdentityAuthenticator { } if (!provider.allowsUsersToSignUp()) { - throw new NotAllowUserToSignUpException(provider); + throw new UnauthorizedException(format("'%s' users are not allowed to sign up", provider.getKey())); } String email = user.getEmail(); if (email != null && dbClient.userDao().doesEmailExist(dbSession, email)) { - throw new EmailAlreadyExistsException(email); + throw new UnauthorizedException(format( + "You can't sign up because email '%s' is already used by an existing user. This means that you probably already registered with another account.", email)); } userUpdater.create(dbSession, NewUser.create() diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/InitFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/InitFilterTest.java index 65cb212bbeb..532d45430c0 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/InitFilterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/InitFilterTest.java @@ -30,6 +30,7 @@ import org.sonar.api.server.authentication.BaseIdentityProvider; import org.sonar.api.server.authentication.Display; import org.sonar.api.server.authentication.IdentityProvider; import org.sonar.api.server.authentication.OAuth2IdentityProvider; +import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; @@ -144,33 +145,22 @@ public class InitFilterTest { } @Test - public void redirect_when_failing_because_of_NotAllowUserToSignUpException() throws Exception { - IdentityProvider identityProvider = new FailWithNotAllowUserToSignUpIdProvider("failing"); + public void redirect_when_failing_because_of_UnauthorizedExceptionException() throws Exception { + IdentityProvider identityProvider = new FailWithUnauthorizedExceptionIdProvider("failing"); when(request.getRequestURI()).thenReturn("/sessions/init/" + identityProvider.getKey()); identityProviderRepository.addIdentityProvider(identityProvider); underTest.doFilter(request, response, chain); - verify(response).sendRedirect("/sessions/not_allowed_to_sign_up?providerName=Failing provider"); + verify(response).sendRedirect("/sessions/unauthorized?message=Email+john%40email.com+is+already+used"); } - @Test - public void redirect_when_failing_because_of_EmailAlreadyExistsException() throws Exception { - IdentityProvider identityProvider = new FailWithEmailAlreadyExistsExceptionIdProvider("failing"); - when(request.getRequestURI()).thenReturn("/sessions/init/" + identityProvider.getKey()); - identityProviderRepository.addIdentityProvider(identityProvider); - - underTest.doFilter(request, response, chain); - - verify(response).sendRedirect("/sessions/email_already_exists?email=john@email.com"); - } - - private void assertOAuth2InitCalled(){ + private void assertOAuth2InitCalled() { assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); assertThat(oAuth2IdentityProvider.isInitCalled()).isTrue(); } - private void assertBasicInitCalled(){ + private void assertBasicInitCalled() { assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); assertThat(baseIdentityProvider.isInitCalled()).isTrue(); } @@ -181,32 +171,15 @@ public class InitFilterTest { assertThat(oAuth2IdentityProvider.isInitCalled()).isFalse(); } - private static class FailWithNotAllowUserToSignUpIdProvider extends FakeBasicIdentityProvider { - - public FailWithNotAllowUserToSignUpIdProvider(String key) { - super(key, true); - } - - @Override - public String getName() { - return "Failing provider"; - } - - @Override - public void init(Context context) { - throw new NotAllowUserToSignUpException(this); - } - } - - private static class FailWithEmailAlreadyExistsExceptionIdProvider extends FakeBasicIdentityProvider { + private static class FailWithUnauthorizedExceptionIdProvider extends FakeBasicIdentityProvider { - public FailWithEmailAlreadyExistsExceptionIdProvider(String key) { + public FailWithUnauthorizedExceptionIdProvider(String key) { super(key, true); } @Override public void init(Context context) { - throw new EmailAlreadyExistsException("john@email.com"); + throw new UnauthorizedException("Email john@email.com is already used"); } } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java index e8e6c765916..04d58e6928e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java @@ -27,6 +27,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.server.authentication.OAuth2IdentityProvider; +import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; @@ -100,6 +101,19 @@ public class OAuth2CallbackFilterTest { assertError("Fail to callback authentication with github"); } + @Test + public void redirect_when_failing_because_of_UnauthorizedExceptionException() throws Exception { + TestIdentityProvider identityProvider = new FailWithUnauthorizedExceptionIdProvider() + .setKey("failing") + .setEnabled(true); + when(request.getRequestURI()).thenReturn("/oauth2/callback/" + identityProvider.getKey()); + identityProviderRepository.addIdentityProvider(identityProvider); + + underTest.doFilter(request, response, chain); + + verify(response).sendRedirect("/sessions/unauthorized?message=Email+john%40email.com+is+already+used"); + } + private void assertCallbackCalled(){ assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); assertThat(oAuth2IdentityProvider.isCallbackCalled()).isTrue(); @@ -111,4 +125,17 @@ public class OAuth2CallbackFilterTest { assertThat(oAuth2IdentityProvider.isInitCalled()).isFalse(); } + private static class FailWithUnauthorizedExceptionIdProvider extends TestIdentityProvider implements OAuth2IdentityProvider { + + @Override + public void init(InitContext context) { + + } + + @Override + public void callback(CallbackContext context) { + throw new UnauthorizedException("Email john@email.com is already used"); + } + } + } diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/UserIdentityAuthenticatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/UserIdentityAuthenticatorTest.java index 6b32b960b16..d0cfc2f72c1 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/UserIdentityAuthenticatorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/UserIdentityAuthenticatorTest.java @@ -25,6 +25,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.ArgumentCaptor; +import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.server.authentication.UserIdentity; import org.sonar.db.DbClient; import org.sonar.db.DbSession; @@ -144,7 +145,8 @@ public class UserIdentityAuthenticatorTest { .setEnabled(true) .setAllowsUsersToSignUp(false); - thrown.expect(NotAllowUserToSignUpException.class); + thrown.expect(UnauthorizedException.class); + thrown.expectMessage("'github' users are not allowed to sign up"); underTest.authenticate(USER_IDENTITY, identityProvider, httpSession); } @@ -154,7 +156,8 @@ public class UserIdentityAuthenticatorTest { when(userDao.selectOrFailByLogin(dbSession, USER_IDENTITY.getLogin())).thenReturn(ACTIVE_USER); when(userDao.doesEmailExist(dbSession, USER_IDENTITY.getEmail())).thenReturn(true); - thrown.expect(EmailAlreadyExistsException.class); + thrown.expect(UnauthorizedException.class); + thrown.expectMessage("You can't sign up because email 'john@email.com' is already used by an existing user. This means that you probably already registered with another account."); underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, httpSession); } } diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/sessions_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/sessions_controller.rb index 535c53b7a4d..5385d577fb1 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/sessions_controller.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/sessions_controller.rb @@ -70,11 +70,4 @@ class SessionsController < ApplicationController end end - def unauthorized - flash[:error] = session['error'] - session['error'] = nil - params[:layout]='false' - render :action => 'unauthorized' - end - end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/email_already_exists.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/email_already_exists.erb deleted file mode 100644 index 559e0ec39e4..00000000000 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/email_already_exists.erb +++ /dev/null @@ -1,11 +0,0 @@ -<table class="spaced"> - <tr> - <td align="center"> - <div id="login_form"> - <p id="unauthorized">You can't sign up because email '<%= h params[:email] %>' is already used by an existing user. This means that you probably already registered with another account.</p> - </div> - <br/> - <a class="spacer-left" href="<%= home_path -%>"><%= message('layout.home') -%></a> - </td> - </tr> -</table> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/not_allowed_to_sign_up.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/not_allowed_to_sign_up.html.erb deleted file mode 100644 index 2208ad0aebd..00000000000 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/not_allowed_to_sign_up.html.erb +++ /dev/null @@ -1,11 +0,0 @@ -<table class="spaced"> - <tr> - <td align="center"> - <div id="login_form"> - <p id="unauthorized"><%= h params[:providerName] %> users are not allowed to sign up</p> - </div> - <br/> - <a class="spacer-left" href="<%= home_path -%>"><%= message('layout.home') -%></a> - </td> - </tr> -</table> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/unauthorized.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/unauthorized.html.erb index a7fe781a829..dee79e3add7 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/unauthorized.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/unauthorized.html.erb @@ -1,15 +1,14 @@ <table class="spaced"> <tr> <td align="center"> - - <% if flash[:error] %> - <div class="error"><%= flash[:error] %></div> - <% end %> - <div id="login_form"> <p id="unauthorized">You're not authorized to access this page. Please contact the administrator.</p> </div> <br/> + <% if params[:message] %> + <div id="message">Reason : <%= params[:message] %></div> + <br/> + <% end %> <a class="spacer-left" href="<%= home_path -%>"><%= message('layout.home') -%></a> </td> </tr> diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/authentication/UnauthorizedException.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/authentication/UnauthorizedException.java new file mode 100644 index 00000000000..a2713e5d87e --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/authentication/UnauthorizedException.java @@ -0,0 +1,58 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.api.server.authentication; + +import com.google.common.base.Charsets; +import java.io.UnsupportedEncodingException; + +import static java.lang.String.format; +import static java.net.URLEncoder.encode; + +/** + * This exception should be used when a functional error is generated by an Identity Provider plugin. + * The user will be redirected to an unauthorized page and the exception's message will be displayed in the UI. + * + * @since 5.5 + */ +public class UnauthorizedException extends RuntimeException { + + public static final String UNAUTHORIZED_PATH = "/sessions/unauthorized"; + private static final String UNAUTHORIZED_PATH_WITH_MESSAGE = UNAUTHORIZED_PATH + "?message=%s"; + + public UnauthorizedException(String message) { + super(message); + } + + public UnauthorizedException(String message, Throwable cause) { + super(message, cause); + } + + public String getPath() { + return format(UNAUTHORIZED_PATH_WITH_MESSAGE, encodeMessage(getMessage())); + } + + private static String encodeMessage(String message) { + try { + return encode(message, Charsets.UTF_8.name()); + } catch (UnsupportedEncodingException unsupportedException) { + throw new IllegalStateException(format("Fail to encode %s", message), unsupportedException); + } + } +} |