Sfoglia il codice sorgente

Fix #80 - Cannot access accounts with proxy header auth

Bubka 3 anni fa
parent
commit
abce20419b

+ 1 - 1
app/Exceptions/Handler.php

@@ -67,7 +67,7 @@ class Handler extends ExceptionHandler
             }
             else {
                 return response()->json([
-                    'message' => $exception->getMessage()], $exception->getCode());
+                    'message' => $exception->getMessage()], 401);
             }
         });
     }

+ 3 - 6
app/Http/Middleware/Authenticate.php

@@ -3,7 +3,6 @@
 namespace App\Http\Middleware;
 
 use Illuminate\Auth\Middleware\Authenticate as Middleware;
-use Illuminate\Support\Arr;
 
 class Authenticate extends Middleware
 {
@@ -23,13 +22,11 @@ class Authenticate extends Middleware
             $guards = [null];
         }
         else {
-            // We inject the reserve-proxy guard to ensure it will be available for every routes
-            // besides their declared guards. This way we ensure priority to declared guards and
-            // a fallback to the reverse-proxy guard
+            // We replace routes guard by the reverse proxy guard if necessary 
             $proxyGuard = 'reverse-proxy-guard';
 
-            if (config('auth.defaults.guard') === $proxyGuard && !Arr::has($guards, $proxyGuard)) {
-                $guards[] = $proxyGuard;
+            if (config('auth.defaults.guard') === $proxyGuard) {
+                $guards = [$proxyGuard];
             }
         }
 

+ 5 - 0
resources/js/api.js

@@ -40,6 +40,11 @@ Vue.axios.interceptors.response.use(response => response, error => {
         routeName = 'login'
     }
 
+    if ( error.response.status === 407 ) {
+        router.push({ name: 'genericError', params: { err: error.response, closable: false } })
+        throw new Vue.axios.Cancel();
+    }
+
     // api calls are stateless so when user inactivity is detected
     // by the backend middleware it cannot logout the user directly
     // so it returns a 418 response.

+ 14 - 9
resources/js/routes.js

@@ -48,12 +48,12 @@ const router = new Router({
         { path: '/settings/webauthn', name: 'settings.webauthn', component: SettingsWebAuthn, meta: { requiresAuth: true } },
         { path: '/settings/oauth/pat/create', name: 'settings.oauth.generatePAT', component: GeneratePAT, meta: { requiresAuth: true } },
 
-        { path: '/login', name: 'login', component: Login },
-        { path: '/register', name: 'register', component: Register },
-        { path: '/password/request', name: 'password.request', component: PasswordRequest },
-        { path: '/password/reset/:token', name: 'password.reset', component: PasswordReset },
-        { path: '/webauthn/lost', name: 'webauthn.lost', component: WebauthnLost },
-        { path: '/webauthn/recover', name: 'webauthn.recover', component: WebauthnRecover },
+        { path: '/login', name: 'login', component: Login, meta: { disabledWithAuthProxy: true } },
+        { path: '/register', name: 'register', component: Register, meta: { disabledWithAuthProxy: true } },
+        { path: '/password/request', name: 'password.request', component: PasswordRequest, meta: { disabledWithAuthProxy: true } },
+        { path: '/password/reset/:token', name: 'password.reset', component: PasswordReset, meta: { disabledWithAuthProxy: true } },
+        { path: '/webauthn/lost', name: 'webauthn.lost', component: WebauthnLost, meta: { disabledWithAuthProxy: true } },
+        { path: '/webauthn/recover', name: 'webauthn.recover', component: WebauthnRecover, meta: { disabledWithAuthProxy: true } },
         { path: '/flooded', name: 'flooded',component: Errors,props: true },
         { path: '/error', name: 'genericError',component: Errors,props: true },
         { path: '/404', name: '404',component: Errors,props: true },
@@ -63,15 +63,20 @@ const router = new Router({
 
 let isFirstLoad = true;
 
-router.beforeEach((to, from, next) => {   
+router.beforeEach((to, from, next) => {
 
     if( to.name === 'accounts') {
         to.params.isFirstLoad = isFirstLoad ? true : false
         isFirstLoad = false;
     }
 
-    next()
-
+    if (to.matched.some(record => record.meta.disabledWithAuthProxy)) {
+        if (window.appConfig.proxyAuth) {
+            next({ name: 'accounts' })
+        }
+        else next()
+    }
+    else next()
 });
 
 router.afterEach(to => {

+ 25 - 17
resources/js/views/Error.vue

@@ -1,6 +1,6 @@
 <template>
     <div class="error-message">
-        <modal v-model="ShowModal">
+        <modal v-model="ShowModal" :closable="this.showcloseButton">
             <div class="error-message" v-if="$route.name == '404'">
                 <p class="error-404"></p>
                 <p>{{ $t('errors.resource_not_found') }}</p>
@@ -17,9 +17,9 @@
             <div v-else>
                 <p class="error-generic"></p>
                 <p>{{ $t('errors.error_occured') }} </p>
-                <p v-if="error" class="has-text-grey-lighter">{{ error.message }}</p>
+                <p v-if="error.message" class="has-text-grey-lighter">{{ error.message }}</p>
                 <p v-if="error.originalMessage" class="has-text-grey-lighter">{{ error.originalMessage }}</p>
-                <p><router-link :to="{ name: 'accounts' }" class="is-text">{{ $t('errors.refresh') }}</router-link></p>
+                <p><router-link :to="{ name: 'accounts', params: { toRefresh: true } }" class="is-text">{{ $t('errors.refresh') }}</router-link></p>
                 <p v-if="debugMode == 'development' && error.debug">
                     <br>
                     {{ error.debug }}
@@ -37,6 +37,7 @@
         data(){
             return {
                 ShowModal : true,
+                showcloseButton: this.closable,
             }
         },
 
@@ -47,17 +48,21 @@
             },
 
             error: function() {
-                if( this.err == null ) {
+                if( this.err === null || this.err === undefined ) {
                     return false
                 }
                 else
                 {
-                    if(this.err.data) {
-                        console.log(this.err.data)
+                    if (this.err.status === 407) {
+                        return {
+                            'message' : this.$t('errors.auth_proxy_failed'),
+                            'originalMessage' : this.$t('errors.auth_proxy_failed_legend')
+                        }
+                    }
+                    else if(this.err.data) {
                         return this.err.data
                     }
-                    else
-                    {
+                    else {
                         return { 'message' : this.err }
                     }
 
@@ -66,7 +71,13 @@
 
         },
 
-        props: ['err'], // on object (error.response) or a string
+        props: {
+            err: [String, Object], // on object (error.response) or a string
+            closable: {
+                type: Boolean,
+                default: true
+            }
+        }, 
 
         components: {
             Modal
@@ -81,14 +92,11 @@
         },
 
         beforeRouteEnter (to, from, next) {
-
-            next(vm => {
-                if( !vm.err ) {
-                    next({ name: 'accounts' });
-                }
-            });
-
-            next();
+            // return to home if no err is provided to prevent an empty error message
+            if (to.params.err == undefined) {
+                next({ name: 'accounts' });
+            }
+            else next()
         },
     }
 

+ 2 - 0
resources/lang/en/errors.php

@@ -37,4 +37,6 @@ return [
     'security_device_unsupported' => 'Security device unsupported',
     'unsupported_with_reverseproxy' => 'Not applicable when using an auth proxy',
     'user_deletion_failed' => 'User account deletion failed, no data have been deleted',
+    'auth_proxy_failed' => 'Proxy authentication failed',
+    'auth_proxy_failed_legend' => '2Fauth is configured to run behind an authentication proxy but your proxy does not return the expected header. Check your configuration and try again.'
 ];