This is an automated email from the ASF dual-hosted git repository.

pan3793 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new e887d7c414 [ZEPPELIN-6528] Handle forbidden interpreter responses in 
classic UI
e887d7c414 is described below

commit e887d7c41403d4dcd16114aa361f2097058e7bcf
Author: Jongyoul Lee <[email protected]>
AuthorDate: Wed Aug 12 16:10:01 2026 +0900

    [ZEPPELIN-6528] Handle forbidden interpreter responses in classic UI
    
    ### What is this PR for?
    
    Apache Shiro 2.0.6 returns HTTP 403 for an authenticated user who lacks a 
required role. Shiro 1.13.0 returned HTTP 401 for the same authorization denial.
    
    The classic interpreter page only handled HTTP 401, so a 403 response did 
not show the permission error toast or redirect the user. This also caused 
`AuthenticationIT.testAnyOfRolesUser` to fail with `Expected ngToast not found`.
    
    This PR handles both 401 and 403 responses and adds controller tests 
covering both statuses.
    
    ### What type of PR is it?
    
    Bug Fix
    
    ### Todos
    
    * [x] Handle HTTP 403 authorization denials in the classic interpreter page
    * [x] Preserve the existing HTTP 401 behavior
    * [x] Add regression tests for both response statuses
    
    ### What is the Jira issue?
    
    * https://issues.apache.org/jira/browse/ZEPPELIN-6528
    
    ### How should this be tested?
    
    ```bash
    cd zeppelin-web
    npm run karma-test -- --single-run
    ```
    
    Local validation:
    
    * ESLint passed for the changed controller and test.
    * `git diff --check` passed.
    * Karma compiled the application and test bundle successfully, but the 
browser run could not start locally because Firefox is not installed in the 
worktree environment.
    
    ### Screenshots
    
    N/A
    
    ### Questions
    
    * Does the license files need to update? No
    * Is there breaking changes for older versions? No
    * Does this need documentation? No
    
    
    Closes #5416 from jongyoul/codex/ZEPPELIN-6528-handle-shiro-403.
    
    Signed-off-by: Cheng Pan <[email protected]>
---
 .../src/app/interpreter/interpreter.controller.js  |  2 +-
 .../app/interpreter/interpreter.controller.test.js | 68 ++++++++++++++++++++++
 2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/zeppelin-web/src/app/interpreter/interpreter.controller.js 
b/zeppelin-web/src/app/interpreter/interpreter.controller.js
index dddae0022c..63db4d1525 100644
--- a/zeppelin-web/src/app/interpreter/interpreter.controller.js
+++ b/zeppelin-web/src/app/interpreter/interpreter.controller.js
@@ -114,7 +114,7 @@ function InterpreterCtrl($rootScope, $scope, $http, 
baseUrlSrv, ngToast, $timeou
         $scope.interpreterSettings = res.data.body;
         checkDownloadingDependencies();
       }).catch(function(res) {
-        if (res.status === 401) {
+        if (res.status === 401 || res.status === 403) {
           ngToast.danger({
             content: 'You don\'t have permission on this page',
             verticalPosition: 'bottom',
diff --git a/zeppelin-web/src/app/interpreter/interpreter.controller.test.js 
b/zeppelin-web/src/app/interpreter/interpreter.controller.test.js
new file mode 100644
index 0000000000..0ceb6afda3
--- /dev/null
+++ b/zeppelin-web/src/app/interpreter/interpreter.controller.test.js
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+describe('Controller: Interpreter', function() {
+  beforeEach(angular.mock.module('zeppelinWebApp'));
+
+  const baseUrlSrvMock = {
+    getBase: () => '/',
+    getRestApiBase: () => '',
+  };
+
+  let $controller;
+  let $httpBackend;
+  let $rootScope;
+  let ngToast;
+
+  beforeEach(inject((_$controller_, _$httpBackend_, _$rootScope_, _ngToast_) 
=> {
+    $controller = _$controller_;
+    $httpBackend = _$httpBackend_;
+    $rootScope = _$rootScope_;
+    ngToast = _ngToast_;
+  }));
+
+  afterEach(function() {
+    $httpBackend.verifyNoOutstandingExpectation();
+    $httpBackend.verifyNoOutstandingRequest();
+  });
+
+  [401, 403].forEach((status) => {
+    it(`should display an authorization error for HTTP ${status}`, function() {
+      spyOn(ngToast, 'danger');
+      spyOn(window, 'setTimeout');
+
+      $httpBackend.expectGET('/interpreter/property/types').respond(200, 
{body: []});
+      $httpBackend.expectGET('/interpreter/setting').respond(status, {});
+      $httpBackend.expectGET('/interpreter').respond(200, {body: []});
+      $httpBackend.expectGET('/interpreter/repository').respond(200, {body: 
[]});
+
+      $controller('InterpreterCtrl', {
+        $scope: $rootScope.$new(),
+        baseUrlSrv: baseUrlSrvMock,
+        $route: {current: {$$route: {originalPath: '/interpreter'}}},
+      });
+      $httpBackend.flush();
+
+      expect(ngToast.danger).toHaveBeenCalledWith({
+        content: 'You don\'t have permission on this page',
+        verticalPosition: 'bottom',
+        timeout: '3000',
+      });
+      expect(window.setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 
3000);
+    });
+  });
+});

Reply via email to