Showing
5 changed files
with
71 additions
and
5 deletions
... | ... | @@ -79,11 +79,18 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
79 | 79 | @Qualifier("oauth2AuthenticationSuccessHandler") |
80 | 80 | private AuthenticationSuccessHandler oauth2AuthenticationSuccessHandler; |
81 | 81 | |
82 | + @Autowired(required = false) | |
83 | + @Qualifier("oauth2AuthenticationFailureHandler") | |
84 | + private AuthenticationFailureHandler oauth2AuthenticationFailureHandler; | |
85 | + | |
82 | 86 | @Autowired |
83 | 87 | @Qualifier("defaultAuthenticationSuccessHandler") |
84 | 88 | private AuthenticationSuccessHandler successHandler; |
85 | 89 | |
86 | - @Autowired private AuthenticationFailureHandler failureHandler; | |
90 | + @Autowired | |
91 | + @Qualifier("defaultAuthenticationFailureHandler") | |
92 | + private AuthenticationFailureHandler failureHandler; | |
93 | + | |
87 | 94 | @Autowired private RestAuthenticationProvider restAuthenticationProvider; |
88 | 95 | @Autowired private JwtAuthenticationProvider jwtAuthenticationProvider; |
89 | 96 | @Autowired private RefreshTokenAuthenticationProvider refreshTokenAuthenticationProvider; |
... | ... | @@ -205,7 +212,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
205 | 212 | .loginPage("/oauth2Login") |
206 | 213 | .loginProcessingUrl(oauth2Configuration.getLoginProcessingUrl()) |
207 | 214 | .successHandler(oauth2AuthenticationSuccessHandler) |
208 | - .failureHandler(failureHandler); | |
215 | + .failureHandler(oauth2AuthenticationFailureHandler); | |
209 | 216 | } |
210 | 217 | } |
211 | 218 | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.oauth2; | |
17 | + | |
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | |
19 | +import org.springframework.security.core.AuthenticationException; | |
20 | +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; | |
21 | +import org.springframework.stereotype.Component; | |
22 | +import org.thingsboard.server.utils.MiscUtils; | |
23 | + | |
24 | +import javax.servlet.ServletException; | |
25 | +import javax.servlet.http.HttpServletRequest; | |
26 | +import javax.servlet.http.HttpServletResponse; | |
27 | +import java.io.IOException; | |
28 | +import java.net.URLEncoder; | |
29 | +import java.nio.charset.StandardCharsets; | |
30 | + | |
31 | +@Component(value = "oauth2AuthenticationFailureHandler") | |
32 | +@ConditionalOnProperty(prefix = "security.oauth2", value = "enabled", havingValue = "true") | |
33 | +public class Oauth2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { | |
34 | + | |
35 | + @Override | |
36 | + public void onAuthenticationFailure(HttpServletRequest request, | |
37 | + HttpServletResponse response, AuthenticationException exception) | |
38 | + throws IOException, ServletException { | |
39 | + String baseUrl = MiscUtils.constructBaseUrl(request); | |
40 | + getRedirectStrategy().sendRedirect(request, response, baseUrl + "/login?loginError=" + | |
41 | + URLEncoder.encode(exception.getMessage(), StandardCharsets.UTF_8.toString())); | |
42 | + } | |
43 | +} | ... | ... |
... | ... | @@ -26,7 +26,7 @@ import javax.servlet.http.HttpServletRequest; |
26 | 26 | import javax.servlet.http.HttpServletResponse; |
27 | 27 | import java.io.IOException; |
28 | 28 | |
29 | -@Component | |
29 | +@Component(value = "defaultAuthenticationFailureHandler") | |
30 | 30 | public class RestAwareAuthenticationFailureHandler implements AuthenticationFailureHandler { |
31 | 31 | |
32 | 32 | private final ThingsboardErrorResponseHandler errorResponseHandler; | ... | ... |
... | ... | @@ -22,7 +22,7 @@ export default angular.module('thingsboard.api.user', [thingsboardApiLogin, |
22 | 22 | .name; |
23 | 23 | |
24 | 24 | /*@ngInject*/ |
25 | -function UserService($http, $q, $rootScope, adminService, dashboardService, timeService, loginService, toast, store, jwtHelper, $translate, $state, $location) { | |
25 | +function UserService($http, $q, $rootScope, adminService, dashboardService, timeService, loginService, toast, store, jwtHelper, $translate, $state, $location, $mdDialog) { | |
26 | 26 | var currentUser = null, |
27 | 27 | currentUserDetails = null, |
28 | 28 | lastPublicDashboardId = null, |
... | ... | @@ -406,6 +406,10 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, time |
406 | 406 | }, function fail() { |
407 | 407 | deferred.reject(); |
408 | 408 | }); |
409 | + } else if (locationSearch.loginError) { | |
410 | + showLoginErrorDialog(locationSearch.loginError); | |
411 | + $location.search('loginError', null); | |
412 | + deferred.reject(); | |
409 | 413 | } else { |
410 | 414 | procceedJwtTokenValidate(); |
411 | 415 | } |
... | ... | @@ -415,6 +419,17 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, time |
415 | 419 | return deferred.promise; |
416 | 420 | } |
417 | 421 | |
422 | + function showLoginErrorDialog(loginError) { | |
423 | + $translate(['login.error', | |
424 | + 'action.close']).then(function (translations) { | |
425 | + var alert = $mdDialog.alert() | |
426 | + .title(translations['login.error']) | |
427 | + .htmlContent(loginError) | |
428 | + .ok(translations['action.close']); | |
429 | + $mdDialog.show(alert); | |
430 | + }); | |
431 | + } | |
432 | + | |
418 | 433 | function loadIsUserTokenAccessEnabled() { |
419 | 434 | var deferred = $q.defer(); |
420 | 435 | if (currentUser.authority === 'SYS_ADMIN' || currentUser.authority === 'TENANT_ADMIN') { | ... | ... |
... | ... | @@ -1334,7 +1334,8 @@ |
1334 | 1334 | "password-link-sent-message": "Password reset link was successfully sent!", |
1335 | 1335 | "email": "Email", |
1336 | 1336 | "login-with": "Login with {{name}}", |
1337 | - "or": "or" | |
1337 | + "or": "or", | |
1338 | + "error": "Login error" | |
1338 | 1339 | }, |
1339 | 1340 | "position": { |
1340 | 1341 | "top": "Top", | ... | ... |