From a9faa3ea9b6a7228ec32d7d58534d69fff6a3ddb Mon Sep 17 00:00:00 2001 From: Steven Zhang Date: Tue, 6 Oct 2026 15:16:42 -0700 Subject: [PATCH] #1336 [Enhancement] UI shows "no role assigned" message when the mapped role of a server user is empty --- admin/src/main/scala/com/neu/api/Api.scala | 5 +- .../scala/com/neu/client/RestClient.scala | 11 ++- .../scala/com/neu/service/BaseService.scala | 22 +++--- .../authentication/OpenIdAuthService.scala | 31 ++++++-- .../authentication/SamlAuthService.scala | 20 +++++- .../service/dashboard/DashboardService.scala | 25 +------ .../neu/service/device/DeviceService.scala | 70 +++---------------- .../com/neu/service/group/GroupService.scala | 30 ++------ .../notification/NotificationService.scala | 40 ++--------- .../neu/service/policy/PolicyService.scala | 51 ++------------ .../com/neu/service/risk/RiskService.scala | 37 ++-------- admin/webapp/websrc/app/app.component.ts | 5 +- .../app/core/interceptor/auth.interceptor.ts | 28 +++++--- .../routes/pages/login/login.component.html | 8 +-- .../app/routes/pages/login/login.component.ts | 12 +++- admin/webapp/websrc/app/routes/routes.ts | 2 +- .../webapp/websrc/assets/i18n/en-common.json | 1 + .../websrc/assets/i18n/zh_cn-common.json | 1 + 18 files changed, 141 insertions(+), 258 deletions(-) diff --git a/admin/src/main/scala/com/neu/api/Api.scala b/admin/src/main/scala/com/neu/api/Api.scala index 5c1cfd7e0..46afd8846 100644 --- a/admin/src/main/scala/com/neu/api/Api.scala +++ b/admin/src/main/scala/com/neu/api/Api.scala @@ -42,9 +42,6 @@ trait Api extends Directives with CoreActors with Core { private val managerPathPrefix: Option[String] = sys.env.get("PATH_PREFIX").map(_.trim).filter(_.nonEmpty) - private final val timeOutStatus = "Status: 408" - private final val authenticationFailedStatus = "Status: 401" - private final val serverErrorStatus = "Status: 503" implicit def exceptionHandler: ExceptionHandler = ExceptionHandler { @@ -57,7 +54,7 @@ trait Api extends Directives with CoreActors with Core { ) case e: Exception => val (status, message) = - handleError(timeOutStatus, authenticationFailedStatus, serverErrorStatus, e) + handleError(e) complete( HttpResponse( status = status, diff --git a/admin/src/main/scala/com/neu/client/RestClient.scala b/admin/src/main/scala/com/neu/client/RestClient.scala index c94d9b6b8..26204a1be 100644 --- a/admin/src/main/scala/com/neu/client/RestClient.scala +++ b/admin/src/main/scala/com/neu/client/RestClient.scala @@ -297,19 +297,24 @@ class RestClient()(using } def handleError( - timeOutStatus: String, - authenticationFailedStatus: String, - serverErrorStatus: String, e: Throwable ): (StatusCode, String) = { val PERMISSION_DENIED = "Permission denied" val sw = new StringWriter + + val timeOutStatus = "Status: 408" + val authenticationFailedStatus = "Status: 401" + val authorizationFailedStatus = "Status: 403" + val serverErrorStatus = "Status: 503" + e.printStackTrace(new PrintWriter(sw)) logger.warn(sw.toString) if (e.getMessage.contains(timeOutStatus)) { (StatusCodes.RequestTimeout, "Session expired!") } else if (e.getMessage.contains(authenticationFailedStatus)) { (StatusCodes.Unauthorized, "Authentication failed!") + } else if (e.getMessage.contains(authorizationFailedStatus)) { + (StatusCodes.Forbidden, "No role assigned!") } else if (e.getMessage.contains(serverErrorStatus)) { (StatusCodes.ServiceUnavailable, "Server is not available!") } else if (e.getMessage.contains(PERMISSION_DENIED)) { diff --git a/admin/src/main/scala/com/neu/service/BaseService.scala b/admin/src/main/scala/com/neu/service/BaseService.scala index 97d22e7dd..0403ad50e 100644 --- a/admin/src/main/scala/com/neu/service/BaseService.scala +++ b/admin/src/main/scala/com/neu/service/BaseService.scala @@ -59,14 +59,20 @@ open class BaseService extends Directives with LazyLogging { } protected def onUnauthorized(e: HttpResponseException, res: String): StandardRoute = - if (res.contains("\"code\":14")) { - complete((StatusCodes.BadRequest, res)) - } else if (res.contains("\"code\":47")) { - complete((StatusCodes.Unauthorized, blocked)) - } else if (res.contains("\"code\":48")) { - complete((StatusCodes.Unauthorized, passwordExpired)) - } else if (res.contains("\"code\":50")) { - complete(StatusCodes.Unauthorized, authSSODisabledError) + if (e.getMessage.contains("Status: 401")) { + if (res.contains("\"code\":14")) { + complete((StatusCodes.BadRequest, res)) + } else if (res.contains("\"code\":47")) { + complete((StatusCodes.Unauthorized, blocked)) + } else if (res.contains("\"code\":48")) { + complete((StatusCodes.Unauthorized, passwordExpired)) + } else if (res.contains("\"code\":50")) { + complete(StatusCodes.Unauthorized, authSSODisabledError) + } else { + complete((StatusCodes.Unauthorized, authError)) + } + } else if (e.getMessage.contains("Status: 403")) { + complete((StatusCodes.Forbidden, "No role assigned!")) } else { complete((StatusCodes.Unauthorized, authError)) } diff --git a/admin/src/main/scala/com/neu/service/authentication/OpenIdAuthService.scala b/admin/src/main/scala/com/neu/service/authentication/OpenIdAuthService.scala index 961ebdcf5..f16d2784f 100644 --- a/admin/src/main/scala/com/neu/service/authentication/OpenIdAuthService.scala +++ b/admin/src/main/scala/com/neu/service/authentication/OpenIdAuthService.scala @@ -108,7 +108,7 @@ class OpenIdAuthService()(implicit ip: String, host: Option[String], nonce: String - ): Future[Route] = Future { + ): Future[Route] = { logger.info(s"openId-g: state is ${state.get}.") logger.info(s"openId-g: code is ${code.getOrElse("no code")}") logger.info(s"openId-g: host is ${host.getOrElse("no host")}") @@ -134,18 +134,35 @@ class OpenIdAuthService()(implicit logger.info("openId-g: OpenId Login. ") response.status match { - case StatusCodes.OK => + case StatusCodes.OK => val authTokenFuture: Future[String] = Unmarshal(response.entity).to[String] val authToken = Await.result(authTokenFuture, RestClient.waitingLimit.seconds) val userToken: UserTokenNew = AuthenticationManager.parseToken(authToken) logger.info("openId-g: added authToken") AuthenticationManager.putSsoToken(nonce, userToken) - redirect(ROOT_PATH, StatusCodes.Found) - case _ => - logger.warn("openId-g: invalid response. redirect /") - deleteCookie("temp") { - redirect(ROOT_PATH, StatusCodes.MovedPermanently) + Future.successful(redirect(ROOT_PATH, StatusCodes.Found)) + case StatusCodes.TemporaryRedirect => + response.headers.find(_.is("location")) match { + case Some(location) => + logger.info(s"openId-g: temporary redirect to ${location.value}") + val locationParts = location.value.split("#", 2) + val baseUri = Uri(locationParts(0)) + val redirectUri = + if (locationParts.length > 1) baseUri.withFragment(locationParts(1)) + else baseUri + Future.successful( + redirect(redirectUri, StatusCodes.SeeOther) + ) + case None => + Future.successful(complete(StatusCodes.BadGateway)) } + case _ => + logger.warn("openId-g: invalid response. redirect /") + Future.successful( + deleteCookie("temp") { + redirect(ROOT_PATH, StatusCodes.MovedPermanently) + } + ) } } } diff --git a/admin/src/main/scala/com/neu/service/authentication/SamlAuthService.scala b/admin/src/main/scala/com/neu/service/authentication/SamlAuthService.scala index 154560c41..760b41d47 100644 --- a/admin/src/main/scala/com/neu/service/authentication/SamlAuthService.scala +++ b/admin/src/main/scala/com/neu/service/authentication/SamlAuthService.scala @@ -150,14 +150,28 @@ class SamlAuthService()(implicit private def handleAuthResponse(response: HttpResponse, nonce: String): Future[Route] = { logger.info("saml-p: processing auth response.") response.status match { - case StatusCodes.OK => - logger.info(s"saml-p: success, storing token under nonce. redirecting to $rootPath") + case StatusCodes.OK => Unmarshal(response.entity).to[String].map { authToken => val userToken: UserTokenNew = AuthenticationManager.parseToken(authToken) AuthenticationManager.putSsoToken(nonce, userToken) redirect(rootPath, StatusCodes.Found) } - case _ => + case StatusCodes.TemporaryRedirect => + response.headers.find(_.is("location")) match { + case Some(location) => + logger.info(s"saml-p: temporary redirect to ${location.value}") + val locationParts = location.value.split("#", 2) + val baseUri = Uri(locationParts(0)) + val redirectUri = + if (locationParts.length > 1) baseUri.withFragment(locationParts(1)) + else baseUri + Future.successful( + redirect(redirectUri, StatusCodes.SeeOther) + ) + case None => + Future.successful(complete(StatusCodes.BadGateway)) + } + case _ => logger.warn(s"saml-p: ${response.status}. SAML login error. redirect to $rootPath ") // Clear the temp cookie so the browser does not retain a stale nonce Future.successful( diff --git a/admin/src/main/scala/com/neu/service/dashboard/DashboardService.scala b/admin/src/main/scala/com/neu/service/dashboard/DashboardService.scala index 475125680..0bfc25c04 100644 --- a/admin/src/main/scala/com/neu/service/dashboard/DashboardService.scala +++ b/admin/src/main/scala/com/neu/service/dashboard/DashboardService.scala @@ -35,10 +35,6 @@ class DashboardService()(implicit executionContext: ExecutionContext) private final val DENY = "deny" private final val DASHBOARD = "dashboard" - private final val timeOutStatus = "Status: 408" - private final val authenticationFailedStatus = "Status: 401" - private final val serverErrorStatus = "Status: 503" - def getMultiClusterSummary(tokenId: String, clusterId: Option[String]): Route = complete { try { val baseUrl = @@ -118,12 +114,7 @@ class DashboardService()(implicit executionContext: ExecutionContext) ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -422,12 +413,7 @@ class DashboardService()(implicit executionContext: ExecutionContext) dashboardScoreDTO } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -546,12 +532,7 @@ class DashboardService()(implicit executionContext: ExecutionContext) dashboardNotificationDTO } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } diff --git a/admin/src/main/scala/com/neu/service/device/DeviceService.scala b/admin/src/main/scala/com/neu/service/device/DeviceService.scala index 7852559b7..88651cfbd 100644 --- a/admin/src/main/scala/com/neu/service/device/DeviceService.scala +++ b/admin/src/main/scala/com/neu/service/device/DeviceService.scala @@ -27,11 +27,8 @@ import scala.util.control.NonFatal class DeviceService extends Directives with DefaultJsonFormats with LazyLogging { - final val timeOutStatus = "Status: 408" - final val authenticationFailedStatus = "Status: 401" - final val serverErrorStatus = "Status: 503" - private final val benchHostPath = "bench/host" - private var logFile = "/tmp/debug.gz" + private final val benchHostPath = "bench/host" + private var logFile = "/tmp/debug.gz" def getEnforcers(tokenId: String, id: Option[String]): Route = complete { if (id.isEmpty) { @@ -411,12 +408,7 @@ class DeviceService extends Directives with DefaultJsonFormats with LazyLogging } } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -442,12 +434,7 @@ class DeviceService extends Directives with DefaultJsonFormats with LazyLogging ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -472,12 +459,7 @@ class DeviceService extends Directives with DefaultJsonFormats with LazyLogging ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -501,12 +483,7 @@ class DeviceService extends Directives with DefaultJsonFormats with LazyLogging ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -537,12 +514,7 @@ class DeviceService extends Directives with DefaultJsonFormats with LazyLogging } } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -617,28 +589,13 @@ class DeviceService extends Directives with DefaultJsonFormats with LazyLogging ) } case Right(false) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - new RuntimeException("Status: 401") - ) + RestClient.handleError(new RuntimeException("Status: 401")) case Left(error) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - error - ) + RestClient.handleError(error) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -661,12 +618,7 @@ class DeviceService extends Directives with DefaultJsonFormats with LazyLogging } } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } diff --git a/admin/src/main/scala/com/neu/service/group/GroupService.scala b/admin/src/main/scala/com/neu/service/group/GroupService.scala index 4a077accd..bf9233823 100644 --- a/admin/src/main/scala/com/neu/service/group/GroupService.scala +++ b/admin/src/main/scala/com/neu/service/group/GroupService.scala @@ -24,8 +24,6 @@ import scala.util.control.NonFatal class GroupService extends BaseService with DefaultJsonFormats with LazyLogging { - private final val serverErrorStatus = "Status: 503" - def getGroupList(tokenId: String, scope: Option[String], f_kind: Option[String]): Route = complete { var url = s"${baseClusterUri(tokenId)}/group?start=0&brief=true" @@ -643,12 +641,7 @@ class GroupService extends BaseService with DefaultJsonFormats with LazyLogging ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -673,12 +666,7 @@ class GroupService extends BaseService with DefaultJsonFormats with LazyLogging ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -790,12 +778,7 @@ class GroupService extends BaseService with DefaultJsonFormats with LazyLogging ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -820,12 +803,7 @@ class GroupService extends BaseService with DefaultJsonFormats with LazyLogging ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } diff --git a/admin/src/main/scala/com/neu/service/notification/NotificationService.scala b/admin/src/main/scala/com/neu/service/notification/NotificationService.scala index e0794b44a..a32d7047e 100644 --- a/admin/src/main/scala/com/neu/service/notification/NotificationService.scala +++ b/admin/src/main/scala/com/neu/service/notification/NotificationService.scala @@ -39,9 +39,8 @@ class NotificationService()(implicit with DefaultJsonFormats with LazyLogging { - final val serverErrorStatus = "Status: 503" - val topLimit = 5 - val client = "client" + val topLimit = 5 + val client = "client" def getIpLocations(ipList: Array[String]): Route = complete { logger.info("Getting ip locations") @@ -189,12 +188,7 @@ class NotificationService()(implicit pagedRes } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } else { auditStr @@ -425,12 +419,7 @@ class NotificationService()(implicit HttpEntity.Empty } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -441,12 +430,7 @@ class NotificationService()(implicit UserGraphLayout(user, GraphCacheManager.getNodeLayout(user, tokenId)) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -457,12 +441,7 @@ class NotificationService()(implicit BlacklistCacheManager.getBlacklist(user, tokenId) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -475,12 +454,7 @@ class NotificationService()(implicit HttpEntity.Empty } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } diff --git a/admin/src/main/scala/com/neu/service/policy/PolicyService.scala b/admin/src/main/scala/com/neu/service/policy/PolicyService.scala index e4ee913b1..5b5117e78 100644 --- a/admin/src/main/scala/com/neu/service/policy/PolicyService.scala +++ b/admin/src/main/scala/com/neu/service/policy/PolicyService.scala @@ -39,8 +39,6 @@ class PolicyService() extends BaseService with DefaultJsonFormats with LazyLoggi private final val admissionControlTest = "debug/admission/test" private final val fedDeploy = "fed/deploy" - final val serverErrorStatus = "Status: 503" - def deployFedRules(tokenId: String, deployFedRulesConfig: DeployFedRulesConfig): Route = complete { logger.info("Inform rule deployment") @@ -207,12 +205,7 @@ class PolicyService() extends BaseService with DefaultJsonFormats with LazyLoggi ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -238,12 +231,7 @@ class PolicyService() extends BaseService with DefaultJsonFormats with LazyLoggi ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -655,12 +643,7 @@ class PolicyService() extends BaseService with DefaultJsonFormats with LazyLoggi ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -683,12 +666,7 @@ class PolicyService() extends BaseService with DefaultJsonFormats with LazyLoggi ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -709,12 +687,7 @@ class PolicyService() extends BaseService with DefaultJsonFormats with LazyLoggi ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -988,12 +961,7 @@ class PolicyService() extends BaseService with DefaultJsonFormats with LazyLoggi ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -1015,12 +983,7 @@ class PolicyService() extends BaseService with DefaultJsonFormats with LazyLoggi ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } diff --git a/admin/src/main/scala/com/neu/service/risk/RiskService.scala b/admin/src/main/scala/com/neu/service/risk/RiskService.scala index 0408ba246..d9867087e 100644 --- a/admin/src/main/scala/com/neu/service/risk/RiskService.scala +++ b/admin/src/main/scala/com/neu/service/risk/RiskService.scala @@ -31,8 +31,6 @@ class RiskService extends BaseService with DefaultJsonFormats with LazyLogging { private val complianceFilterUrl = "compliance/available_filter" private val vulnerabilityProfileUrl = "vulnerability/profile" - final val serverErrorStatus = "Status: 503" - def queryScannedAssets(tokenId: String, scannedAssetsQuery: ScannedAssetsQuery): Route = complete { logger.info("Getting scanned assets ...") @@ -282,12 +280,7 @@ class RiskService extends BaseService with DefaultJsonFormats with LazyLogging { ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -310,12 +303,7 @@ class RiskService extends BaseService with DefaultJsonFormats with LazyLogging { ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -330,12 +318,7 @@ class RiskService extends BaseService with DefaultJsonFormats with LazyLogging { CisNISTManager.getCompliancesNIST(complianceNISTConfigData.config.names) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -434,12 +417,7 @@ class RiskService extends BaseService with DefaultJsonFormats with LazyLogging { ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } @@ -461,12 +439,7 @@ class RiskService extends BaseService with DefaultJsonFormats with LazyLogging { ) } catch { case NonFatal(e) => - RestClient.handleError( - timeOutStatus, - authenticationFailedStatus, - serverErrorStatus, - e - ) + RestClient.handleError(e) } } } diff --git a/admin/webapp/websrc/app/app.component.ts b/admin/webapp/websrc/app/app.component.ts index efddae3c9..a5aa6cba8 100644 --- a/admin/webapp/websrc/app/app.component.ts +++ b/admin/webapp/websrc/app/app.component.ts @@ -123,7 +123,8 @@ export class AppComponent implements OnInit { this.commonHttpService.getGravatar().subscribe(val => { GlobalVariable.gravatar = val; }); - if (this.win.location.hash !== '#/login' && this.win.location.hash !== '') { + const currentRoute = this.win.location.hash.split('?')[0]; + if (currentRoute !== '#/login' && currentRoute !== '') { this.authService .refreshToken( this.win.location.href.includes(GlobalConstant.PROXY_VALUE) @@ -212,7 +213,7 @@ export class AppComponent implements OnInit { private heartbeat = () => { let currTimer: number = new Date().getTime(); - if (this.win.location.hash !== '#/login') { + if (this.win.location.hash.split('?')[0] !== '#/login') { if (currTimer - this.initTimer > 29000 || this.isFirstAction) { this.isFirstAction = false; this.initTimer = currTimer; diff --git a/admin/webapp/websrc/app/core/interceptor/auth.interceptor.ts b/admin/webapp/websrc/app/core/interceptor/auth.interceptor.ts index 651311308..4d74cc583 100644 --- a/admin/webapp/websrc/app/core/interceptor/auth.interceptor.ts +++ b/admin/webapp/websrc/app/core/interceptor/auth.interceptor.ts @@ -24,20 +24,23 @@ export class AuthInterceptor implements HttpInterceptor { intercept(req: HttpRequest, next: HttpHandler) { console.log('Auth intercepting...'); + if (req.url.includes('/assets/i18n/')) { + return next.handle(req); + } let authToken; try { authToken = this.localStorage.has(GlobalConstant.LOCAL_STORAGE_TOKEN) ? this.localStorage.get(GlobalConstant.LOCAL_STORAGE_TOKEN).token.token : ''; - if ( - !( - req.url.indexOf(PathConstant.LOGIN_URL) >= 0 && - typeof req.method === 'string' && - req.method === 'POST' - ) - ) { + const isLoginRequest = + req.url.indexOf(PathConstant.LOGIN_URL) >= 0 && + typeof req.method === 'string' && + req.method === 'POST'; + if (!isLoginRequest) { if (authToken === '') { - this.router.navigate([GlobalConstant.PATH_LOGIN]); + if (!this.isLoginRoute()) { + this.router.navigate([GlobalConstant.PATH_LOGIN]); + } } else { const authReq = req.clone({ headers: req.headers @@ -52,11 +55,18 @@ export class AuthInterceptor implements HttpInterceptor { if (GlobalVariable.isSUSESSO) { this.localStorage.remove(GlobalConstant.LOCAL_STORAGE_TOKEN); this.router.navigate([GlobalConstant.PATH_LOGOUT]); - } else { + } else if (!this.isLoginRoute()) { this.router.navigate([GlobalConstant.PATH_LOGIN]); } } return next.handle(req); } + + private isLoginRoute(): boolean { + return ( + GlobalVariable.window.location.hash.split('?')[0] === + `#/${GlobalConstant.PATH_LOGIN}` + ); + } } diff --git a/admin/webapp/websrc/app/routes/pages/login/login.component.html b/admin/webapp/websrc/app/routes/pages/login/login.component.html index b35966135..d2de912c5 100644 --- a/admin/webapp/websrc/app/routes/pages/login/login.component.html +++ b/admin/webapp/websrc/app/routes/pages/login/login.component.html @@ -30,9 +30,9 @@ mode="indeterminate">
- {{ authMsg }} + {{ LoginErrorMsg || authMsg | translate }}
-
- {{ authMsg }} +
+ {{ LoginErrorMsg || authMsg | translate }}
{{ 'login.RBAC_ALERT.PASSWORD_RETRIEVAL_ERROR' | translate }} diff --git a/admin/webapp/websrc/app/routes/pages/login/login.component.ts b/admin/webapp/websrc/app/routes/pages/login/login.component.ts index f9779e833..a7b8f4d46 100644 --- a/admin/webapp/websrc/app/routes/pages/login/login.component.ts +++ b/admin/webapp/websrc/app/routes/pages/login/login.component.ts @@ -7,7 +7,7 @@ import { CookieService } from 'ngx-cookie-service'; import { GlobalConstant } from '@common/constants/global.constant'; import { GlobalVariable } from '@common/variables/global.variable'; import { SwitchersService } from '@core/switchers/switchers.service'; -import { Router } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { LOCAL_STORAGE, SESSION_STORAGE, @@ -49,6 +49,8 @@ export class LoginComponent implements OnInit, OnDestroy { public loginForm: FormGroup; public inProgress: boolean = false; public authMsg: string = ''; + public loginErrorStatus: string = ''; + public LoginErrorMsg: string = ''; public servers: Array = []; public showPassword: boolean = false; public isFromSSO: boolean = false; @@ -86,6 +88,7 @@ export class LoginComponent implements OnInit, OnDestroy { private commonHttpService: CommonHttpService, private summaryService: SummaryService, private fb: FormBuilder, + private route: ActivatedRoute, private router: Router, private dialog: MatDialog, private sanitizer: DomSanitizer, @@ -102,6 +105,13 @@ export class LoginComponent implements OnInit, OnDestroy { this.inProgress = false; this.samlEnabled = false; this.oidcEnabled = false; + this.loginErrorStatus = + this.route.snapshot.queryParamMap.get('error') || ''; + const loginErrorMessages: Record = { + '401': 'login.AUTH_ERROR', + '403': 'login.NO_ROLE_ASSIGNED', + }; + this.LoginErrorMsg = loginErrorMessages[this.loginErrorStatus] || ''; this.now = new Date(); this.app = this.switchersService.getAppSwitcher(''); this.localStorage.set('login_time', this.now.toString()); diff --git a/admin/webapp/websrc/app/routes/routes.ts b/admin/webapp/websrc/app/routes/routes.ts index 60b091380..8d9599757 100644 --- a/admin/webapp/websrc/app/routes/routes.ts +++ b/admin/webapp/websrc/app/routes/routes.ts @@ -194,6 +194,6 @@ export const routes: Routes = [ // Not found { path: 'logout', component: LogoutComponent }, { path: 'eula', component: LoginComponent }, - { path: '**', redirectTo: 'login' }, { path: 'login', component: LoginComponent }, + { path: '**', redirectTo: 'login' }, ]; diff --git a/admin/webapp/websrc/assets/i18n/en-common.json b/admin/webapp/websrc/assets/i18n/en-common.json index 3928db9ab..ed67e4ade 100644 --- a/admin/webapp/websrc/assets/i18n/en-common.json +++ b/admin/webapp/websrc/assets/i18n/en-common.json @@ -232,6 +232,7 @@ "OKTA_LOGIN": "Login with SAML", "OIDC_LOGIN": "Login with OpenID", "AUTH_ERROR": "Authentication failed!", + "NO_ROLE_ASSIGNED": "No role assigned!", "SESSION_TIMEOUT": "Session has expired. Please login.", "CHANGE_DEFAULT_PASSWORD": "You should change the default password!", "CHANGE_DEFAULT_PASSWORD_RANCHER": "NeuVector default admin user's password should be changed!", diff --git a/admin/webapp/websrc/assets/i18n/zh_cn-common.json b/admin/webapp/websrc/assets/i18n/zh_cn-common.json index 9ec99ba01..726477263 100644 --- a/admin/webapp/websrc/assets/i18n/zh_cn-common.json +++ b/admin/webapp/websrc/assets/i18n/zh_cn-common.json @@ -232,6 +232,7 @@ "OKTA_LOGIN": "SAML登录", "OIDC_LOGIN": "OpenID登录", "AUTH_ERROR": "身分验证错误!", + "NO_ROLE_ASSIGNED": "未分配角色!", "SESSION_TIMEOUT": "会话超时,请重新登录", "CHANGE_DEFAULT_PASSWORD": "请修改缺省密码!", "CHANGE_DEFAULT_PASSWORD_RANCHER": "NeuVector的默认Admin的密码应该被修改!",