Shinsuke Sugaya 9 anni fa
parent
commit
bb7f65c957

+ 5 - 0
pom.xml

@@ -1057,6 +1057,11 @@
 			<artifactId>corelib</artifactId>
 			<artifactId>corelib</artifactId>
 			<version>0.3.5</version>
 			<version>0.3.5</version>
 		</dependency>
 		</dependency>
+		<dependency>
+			<groupId>org.codelibs</groupId>
+			<artifactId>spnego</artifactId>
+			<version>1.0-SNAPSHOT</version>
+		</dependency>
 		<dependency>
 		<dependency>
 			<groupId>commons-io</groupId>
 			<groupId>commons-io</groupId>
 			<artifactId>commons-io</artifactId>
 			<artifactId>commons-io</artifactId>

+ 1 - 1
src/main/java/org/codelibs/fess/app/web/base/FessSearchAction.java

@@ -15,12 +15,12 @@
  */
  */
 package org.codelibs.fess.app.web.base;
 package org.codelibs.fess.app.web.base;
 
 
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
 import java.util.Set;
 import java.util.Set;
-import java.util.HashSet;
 
 
 import javax.annotation.Resource;
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequest;

+ 0 - 1
src/main/java/org/codelibs/fess/app/web/login/LoginAction.java

@@ -16,7 +16,6 @@
 package org.codelibs.fess.app.web.login;
 package org.codelibs.fess.app.web.login;
 
 
 import org.codelibs.fess.app.web.base.FessLoginAction;
 import org.codelibs.fess.app.web.base.FessLoginAction;
-import org.codelibs.fess.app.web.base.login.UserPasswordLoginCredential;
 import org.codelibs.fess.util.RenderDataUtil;
 import org.codelibs.fess.util.RenderDataUtil;
 import org.lastaflute.web.Execute;
 import org.lastaflute.web.Execute;
 import org.lastaflute.web.login.exception.LoginFailureException;
 import org.lastaflute.web.login.exception.LoginFailureException;

+ 28 - 0
src/main/java/org/codelibs/fess/exception/ServletRuntimeException.java

@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012-2016 CodeLibs Project and the Others.
+ *
+ * Licensed 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.
+ */
+package org.codelibs.fess.exception;
+
+import javax.servlet.ServletException;
+
+public class ServletRuntimeException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    public ServletRuntimeException(ServletException e) {
+        super(e);
+    }
+
+}

+ 149 - 0
src/main/java/org/codelibs/fess/filter/SpnegoFilter.java

@@ -0,0 +1,149 @@
+/*
+ * Copyright 2012-2016 CodeLibs Project and the Others.
+ *
+ * Licensed 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.
+ */
+package org.codelibs.fess.filter;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.codelibs.core.exception.IORuntimeException;
+import org.codelibs.core.lang.StringUtil;
+import org.codelibs.fess.exception.FessSystemException;
+import org.codelibs.fess.exception.ServletRuntimeException;
+import org.codelibs.fess.mylasta.action.FessUserBean;
+import org.codelibs.fess.util.ComponentUtil;
+import org.codelibs.spnego.SpnegoHttpFilter;
+import org.codelibs.spnego.SpnegoHttpServletRequest;
+
+/**
+ * SpnegoFilter supports Integrated Windows Authentication(SSO).
+ * 
+ * @author shinsuke
+ */
+public class SpnegoFilter extends SpnegoHttpFilter {
+
+    public void init(final FilterConfig filterConfig) throws ServletException {
+        ComponentUtil.processAfterContainerInit(() -> {
+            if (ComponentUtil.getFessConfig().isSsoEnabled()) {
+                initAuthenticator(filterConfig);
+            }
+        });
+    }
+
+    private void initAuthenticator(final FilterConfig filterConfig) {
+        try {
+            super.init(new FilterConfig() {
+
+                @Override
+                public ServletContext getServletContext() {
+                    return filterConfig.getServletContext();
+                }
+
+                @Override
+                public Enumeration<String> getInitParameterNames() {
+                    return filterConfig.getInitParameterNames();
+                }
+
+                @Override
+                public String getInitParameter(String name) {
+                    if (Constants.KRB5_CONF.equals(name)) {
+                        final String krb5Conf = ComponentUtil.getFessConfig().getSpnegoKrb5Conf();
+                        if (StringUtil.isNotBlank(krb5Conf)) {
+                            return krb5Conf;
+                        }
+                    } else if (Constants.LOGIN_CONF.equals(name)) {
+                        final String loginConf = ComponentUtil.getFessConfig().getSpnegoLoginConf();
+                        if (StringUtil.isNotBlank(loginConf)) {
+                            return loginConf;
+                        }
+                    } else if (Constants.PREAUTH_USERNAME.equals(name)) {
+                        final String username = ComponentUtil.getFessConfig().getSpnegoPreauthUsername();
+                        if (StringUtil.isNotBlank(username)) {
+                            return username;
+                        }
+                    } else if (Constants.PREAUTH_PASSWORD.equals(name)) {
+                        final String password = ComponentUtil.getFessConfig().getSpnegoPreauthPassword();
+                        if (StringUtil.isNotBlank(password)) {
+                            return password;
+                        }
+                    }
+                    return filterConfig.getInitParameter(name);
+                }
+
+                @Override
+                public String getFilterName() {
+                    return filterConfig.getFilterName();
+                }
+            });
+        } catch (final ServletException e) {
+            throw new FessSystemException("Initialization failed.", e);
+        }
+    }
+
+    @Override
+    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException,
+            ServletException {
+        try {
+            ComponentUtil.getRequestManager().findUserBean(FessUserBean.class).ifPresent(u -> {
+                doFilter(() -> chain.doFilter(request, response));
+            }).orElse(() -> {
+                if (ComponentUtil.getFessConfig().isSsoEnabled()) {
+                    doFilter(() -> SpnegoFilter.super.doFilter(request, response, chain));
+                } else {
+                    doFilter(() -> chain.doFilter(request, response));
+                }
+            });
+        } catch (final IORuntimeException e) {
+            throw (IOException) e.getCause();
+        } catch (final ServletRuntimeException e) {
+            throw (ServletException) e.getCause();
+        }
+    }
+
+    @Override
+    protected void processRequest(final SpnegoHttpServletRequest request, final ServletResponse response, final FilterChain chain)
+            throws IOException, ServletException {
+        if (StringUtil.isNotBlank(request.getRemoteUser())) {
+            // TODO save path and parameters into session
+            RequestDispatcher dispatcher = request.getRequestDispatcher(ComponentUtil.getFessConfig().getSsoLoginPath());
+            dispatcher.forward(request, response);
+        } else {
+            chain.doFilter(request, response);
+        }
+    }
+
+    protected void doFilter(DoFilterCallback callback) {
+        try {
+            callback.run();
+        } catch (IOException e) {
+            throw new IORuntimeException(e);
+        } catch (ServletException e) {
+            throw new ServletRuntimeException(e);
+        }
+    }
+
+    interface DoFilterCallback {
+
+        void run() throws IOException, ServletException;
+    }
+}

+ 2 - 0
src/main/java/org/codelibs/fess/helper/SystemHelper.java

@@ -102,6 +102,8 @@ public class SystemHelper {
                                 return langItems;
                                 return langItems;
                             }
                             }
                         });
                         });
+
+        ComponentUtil.doInitProcesses(p -> p.run());
     }
     }
 
 
     @PreDestroy
     @PreDestroy

+ 7 - 1
src/main/java/org/codelibs/fess/ldap/LdapManager.java

@@ -85,6 +85,12 @@ public class LdapManager {
                 fessConfig.getLdapProviderUrl(), fessConfig.getLdapSecurityPrincipal(username), password);
                 fessConfig.getLdapProviderUrl(), fessConfig.getLdapSecurityPrincipal(username), password);
     }
     }
 
 
+    protected Hashtable<String, String> createSearchEnv() {
+        final FessConfig fessConfig = ComponentUtil.getFessConfig();
+        return createEnvironment(fessConfig.getLdapInitialContextFactory(), fessConfig.getLdapSecurityAuthentication(),
+                fessConfig.getLdapProviderUrl(), fessConfig.getLdapAdminSecurityPrincipal(), fessConfig.getLdapAdminSecurityCredentials());
+    }
+
     public OptionalEntity<FessUser> login(final String username, final String password) {
     public OptionalEntity<FessUser> login(final String username, final String password) {
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
 
 
@@ -106,7 +112,7 @@ public class LdapManager {
     }
     }
 
 
     public OptionalEntity<FessUser> login(final String username) {
     public OptionalEntity<FessUser> login(final String username) {
-        final Hashtable<String, String> env = createAdminEnv();
+        final Hashtable<String, String> env = createSearchEnv();
         try (DirContextHolder holder = getDirContext(() -> env)) {
         try (DirContextHolder holder = getDirContext(() -> env)) {
             final DirContext context = holder.get();
             final DirContext context = holder.get();
             if (logger.isDebugEnabled()) {
             if (logger.isDebugEnabled()) {

+ 97 - 0
src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java

@@ -928,6 +928,24 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     /** The key of the configuration. e.g. homeDirectory */
     /** The key of the configuration. e.g. homeDirectory */
     String LDAP_ATTR_HOME_DIRECTORY = "ldap.attr.homeDirectory";
     String LDAP_ATTR_HOME_DIRECTORY = "ldap.attr.homeDirectory";
 
 
+    /** The key of the configuration. e.g. false */
+    String SSO_ENABLED = "sso.enabled";
+
+    /** The key of the configuration. e.g. /sso/ */
+    String SSO_LOGIN_PATH = "sso.login.path";
+
+    /** The key of the configuration. e.g. krb5.conf */
+    String SPNEGO_KRB5_CONF = "spnego.krb5.conf";
+
+    /** The key of the configuration. e.g. auth_login.conf */
+    String SPNEGO_LOGIN_CONF = "spnego.login.conf";
+
+    /** The key of the configuration. e.g. username */
+    String SPNEGO_PREAUTH_USERNAME = "spnego.preauth.username";
+
+    /** The key of the configuration. e.g. password */
+    String SPNEGO_PREAUTH_PASSWORD = "spnego.preauth.password";
+
     /**
     /**
      * Get the value of property as {@link String}.
      * Get the value of property as {@link String}.
      * @param propertyKey The key of the property. (NotNull)
      * @param propertyKey The key of the property. (NotNull)
@@ -3722,6 +3740,57 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
      */
      */
     String getLdapAttrHomeDirectory();
     String getLdapAttrHomeDirectory();
 
 
+    /**
+     * Get the value for the key 'sso.enabled'. <br>
+     * The value is, e.g. false <br>
+     * comment: ------
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getSsoEnabled();
+
+    /**
+     * Is the property for the key 'sso.enabled' true? <br>
+     * The value is, e.g. false <br>
+     * comment: ------
+     * @return The determination, true or false. (if not found, exception but basically no way)
+     */
+    boolean isSsoEnabled();
+
+    /**
+     * Get the value for the key 'sso.login.path'. <br>
+     * The value is, e.g. /sso/ <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getSsoLoginPath();
+
+    /**
+     * Get the value for the key 'spnego.krb5.conf'. <br>
+     * The value is, e.g. krb5.conf <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getSpnegoKrb5Conf();
+
+    /**
+     * Get the value for the key 'spnego.login.conf'. <br>
+     * The value is, e.g. auth_login.conf <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getSpnegoLoginConf();
+
+    /**
+     * Get the value for the key 'spnego.preauth.username'. <br>
+     * The value is, e.g. username <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getSpnegoPreauthUsername();
+
+    /**
+     * Get the value for the key 'spnego.preauth.password'. <br>
+     * The value is, e.g. password <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getSpnegoPreauthPassword();
+
     /**
     /**
      * The simple implementation for configuration.
      * The simple implementation for configuration.
      * @author FreeGen
      * @author FreeGen
@@ -5202,5 +5271,33 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
         public String getLdapAttrHomeDirectory() {
         public String getLdapAttrHomeDirectory() {
             return get(FessConfig.LDAP_ATTR_HOME_DIRECTORY);
             return get(FessConfig.LDAP_ATTR_HOME_DIRECTORY);
         }
         }
+
+        public String getSsoEnabled() {
+            return get(FessConfig.SSO_ENABLED);
+        }
+
+        public boolean isSsoEnabled() {
+            return is(FessConfig.SSO_ENABLED);
+        }
+
+        public String getSsoLoginPath() {
+            return get(FessConfig.SSO_LOGIN_PATH);
+        }
+
+        public String getSpnegoKrb5Conf() {
+            return get(FessConfig.SPNEGO_KRB5_CONF);
+        }
+
+        public String getSpnegoLoginConf() {
+            return get(FessConfig.SPNEGO_LOGIN_CONF);
+        }
+
+        public String getSpnegoPreauthUsername() {
+            return get(FessConfig.SPNEGO_PREAUTH_USERNAME);
+        }
+
+        public String getSpnegoPreauthPassword() {
+            return get(FessConfig.SPNEGO_PREAUTH_PASSWORD);
+        }
     }
     }
 }
 }

+ 22 - 0
src/main/java/org/codelibs/fess/util/ComponentUtil.java

@@ -15,6 +15,10 @@
  */
  */
 package org.codelibs.fess.util;
 package org.codelibs.fess.util;
 
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
 import org.apache.lucene.queryparser.classic.QueryParser;
 import org.apache.lucene.queryparser.classic.QueryParser;
 import org.codelibs.core.crypto.CachedCipher;
 import org.codelibs.core.crypto.CachedCipher;
 import org.codelibs.core.misc.DynamicProperties;
 import org.codelibs.core.misc.DynamicProperties;
@@ -153,9 +157,27 @@ public final class ComponentUtil {
 
 
     private static FessConfig fessConfig;
     private static FessConfig fessConfig;
 
 
+    private static List<Runnable> initProcesses = new ArrayList<>();
+
     private ComponentUtil() {
     private ComponentUtil() {
     }
     }
 
 
+    public static void processAfterContainerInit(Runnable process) {
+        if (available()) {
+            process.run();
+        } else {
+            initProcesses.add(process);
+        }
+    }
+
+    public static void doInitProcesses(Consumer<? super Runnable> action) {
+        try {
+            initProcesses.forEach(action);
+        } finally {
+            initProcesses.clear();
+        }
+    }
+
     public static CachedCipher getCipher(final String cipherName) {
     public static CachedCipher getCipher(final String cipherName) {
         return getComponent(cipherName);
         return getComponent(cipherName);
     }
     }

+ 11 - 0
src/main/resources/fess_config.properties

@@ -468,3 +468,14 @@ ldap.attr.departmentNumber=departmentNumber
 ldap.attr.uidNumber=uidNumber
 ldap.attr.uidNumber=uidNumber
 ldap.attr.gidNumber=gidNumber
 ldap.attr.gidNumber=gidNumber
 ldap.attr.homeDirectory=homeDirectory
 ldap.attr.homeDirectory=homeDirectory
+
+# ----------------------------------------------------------
+#                                                      SSO
+#                                                     ------
+sso.enabled=false
+sso.login.path=/sso/
+spnego.krb5.conf=krb5.conf
+spnego.login.conf=auth_login.conf
+spnego.preauth.username=username
+spnego.preauth.password=password
+

+ 53 - 80
src/main/webapp/WEB-INF/web.xml

@@ -55,68 +55,38 @@
     <filter-class>org.lastaflute.web.servlet.filter.LastaToActionFilter</filter-class>
     <filter-class>org.lastaflute.web.servlet.filter.LastaToActionFilter</filter-class>
   </filter>
   </filter>
 
 
-  <!-- SPNEGO    -->
-  <!--
   <filter>
   <filter>
-      <filter-name>SpnegoHttpFilter</filter-name>
-      <filter-class>net.sourceforge.spnego.SpnegoHttpFilter</filter-class>
-
-      <init-param>
-          <param-name>spnego.allow.basic</param-name>
-          <param-value>false</param-value>
-      </init-param>
-
-      <init-param>
-          <param-name>spnego.allow.localhost</param-name>
-          <param-value>true</param-value>
-      </init-param>
-
-      <init-param>
-          <param-name>spnego.allow.unsecure.basic</param-name>
-          <param-value>false</param-value>
-      </init-param>
-
-      <init-param>
-          <param-name>spnego.login.client.module</param-name>
-          <param-value>spnego-client</param-value>
-      </init-param>
-
-      <init-param>
-          <param-name>spnego.krb5.conf</param-name>
-          <param-value>krb5.conf</param-value>
-      </init-param>
-
-      <init-param>
-          <param-name>spnego.login.conf</param-name>
-          <param-value>login.conf</param-value>
-      </init-param>
-
-      <init-param>
-          <param-name>spnego.preauth.username</param-name>
-          <param-value>knldguser</param-value>
-      </init-param>
-
-      <init-param>
-          <param-name>spnego.preauth.password</param-name>
-          <param-value>zaq12wsx</param-value>
-      </init-param>
-
-      <init-param>
-          <param-name>spnego.login.server.module</param-name>
-          <param-value>spnego-server</param-value>
-      </init-param>
-
-      <init-param>
-          <param-name>spnego.prompt.ntlm</param-name>
-          <param-value>false</param-value>
-      </init-param>
-
-      <init-param>
-          <param-name>spnego.logger.level</param-name>
-          <param-value>1</param-value>
-      </init-param>
+    <filter-name>spnegoFilter</filter-name>
+    <filter-class>org.codelibs.fess.filter.SpnegoFilter</filter-class>
+    <init-param>
+      <param-name>spnego.allow.basic</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>spnego.allow.localhost</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>spnego.allow.unsecure.basic</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>spnego.login.client.module</param-name>
+      <param-value>spnego-client</param-value>
+    </init-param>
+    <init-param>
+      <param-name>spnego.login.server.module</param-name>
+      <param-value>spnego-server</param-value>
+    </init-param>
+    <init-param>
+      <param-name>spnego.prompt.ntlm</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>spnego.logger.level</param-name>
+      <param-value>0</param-value>
+    </init-param>
   </filter>
   </filter>
--->
 
 
   <!-- ================================================================================= -->
   <!-- ================================================================================= -->
   <!--                                                                    Filter Mapping -->
   <!--                                                                    Filter Mapping -->
@@ -137,29 +107,28 @@
   </filter-mapping>
   </filter-mapping>
 
 
   <filter-mapping>
   <filter-mapping>
-    <filter-name>webApiFilter</filter-name>
+    <filter-name>spnegoFilter</filter-name>
     <url-pattern>/*</url-pattern>
     <url-pattern>/*</url-pattern>
     <dispatcher>REQUEST</dispatcher>
     <dispatcher>REQUEST</dispatcher>
   </filter-mapping>
   </filter-mapping>
 
 
   <filter-mapping>
   <filter-mapping>
-    <filter-name>lastaShowbaseFilter</filter-name>
+    <filter-name>webApiFilter</filter-name>
     <url-pattern>/*</url-pattern>
     <url-pattern>/*</url-pattern>
     <dispatcher>REQUEST</dispatcher>
     <dispatcher>REQUEST</dispatcher>
   </filter-mapping>
   </filter-mapping>
 
 
   <filter-mapping>
   <filter-mapping>
-    <filter-name>lastaToActionFilter</filter-name>
+    <filter-name>lastaShowbaseFilter</filter-name>
     <url-pattern>/*</url-pattern>
     <url-pattern>/*</url-pattern>
     <dispatcher>REQUEST</dispatcher>
     <dispatcher>REQUEST</dispatcher>
   </filter-mapping>
   </filter-mapping>
 
 
-  <!--
   <filter-mapping>
   <filter-mapping>
-      <filter-name>SpnegoHttpFilter</filter-name>
-      <url-pattern>/*</url-pattern>
+    <filter-name>lastaToActionFilter</filter-name>
+    <url-pattern>/*</url-pattern>
+    <dispatcher>REQUEST</dispatcher>
   </filter-mapping>
   </filter-mapping>
--->
 
 
   <!-- ================================================================================= -->
   <!-- ================================================================================= -->
   <!--                                                                           Servlet -->
   <!--                                                                           Servlet -->
@@ -173,7 +142,7 @@
   <!--                                                                  Servlet Listener -->
   <!--                                                                  Servlet Listener -->
   <!--                                                                  ================ -->
   <!--                                                                  ================ -->
   <listener>
   <listener>
-  	<listener-class>org.apache.commons.fileupload.servlet.FileCleanerCleanup</listener-class>
+    <listener-class>org.apache.commons.fileupload.servlet.FileCleanerCleanup</listener-class>
   </listener>
   </listener>
 
 
   <!-- ================================================================================= -->
   <!-- ================================================================================= -->
@@ -183,7 +152,7 @@
     <session-config>
     <session-config>
         <session-timeout>1</session-timeout>
         <session-timeout>1</session-timeout>
     </session-config>
     </session-config>
-	-->
+  -->
 
 
   <!-- ================================================================================= -->
   <!-- ================================================================================= -->
   <!--                                                                      Welcome File -->
   <!--                                                                      Welcome File -->
@@ -191,7 +160,7 @@
 <!--
 <!--
     <welcome-file-list>
     <welcome-file-list>
     </welcome-file-list>
     </welcome-file-list>
-	-->
+  -->
 
 
   <!-- ================================================================================= -->
   <!-- ================================================================================= -->
   <!--                                                                        JSP Config -->
   <!--                                                                        JSP Config -->
@@ -210,23 +179,27 @@
   <!--                                                                        Error Page -->
   <!--                                                                        Error Page -->
   <!--                                                                        ========== -->
   <!--                                                                        ========== -->
   <error-page>
   <error-page>
-  	<error-code>400</error-code>
-  	<location>/WEB-INF/view/error/redirect.jsp?type=badRequest</location>
+    <error-code>400</error-code>
+    <location>/WEB-INF/view/error/redirect.jsp?type=badRequest</location>
+  </error-page>
+  <error-page>
+    <error-code>401</error-code>
+    <location>/WEB-INF/view/error/redirect.jsp?type=badAuth</location>
   </error-page>
   </error-page>
   <error-page>
   <error-page>
-  	<error-code>403</error-code>
-  	<location>/WEB-INF/view/error/redirect.jsp?type=logOut</location>
+    <error-code>403</error-code>
+    <location>/WEB-INF/view/error/redirect.jsp?type=logOut</location>
   </error-page>
   </error-page>
   <error-page>
   <error-page>
-  	<error-code>404</error-code>
-  	<location>/WEB-INF/view/error/redirect.jsp?type=notFound</location>
+    <error-code>404</error-code>
+    <location>/WEB-INF/view/error/redirect.jsp?type=notFound</location>
   </error-page>
   </error-page>
   <error-page>
   <error-page>
-  	<error-code>408</error-code>
-  	<location>/WEB-INF/view/error/redirect.jsp?type=logOut</location>
+    <error-code>408</error-code>
+    <location>/WEB-INF/view/error/redirect.jsp?type=logOut</location>
   </error-page>
   </error-page>
   <error-page>
   <error-page>
-  	<error-code>500</error-code>
-  	<location>/WEB-INF/view/error/redirect.jsp?type=systemError</location>
+    <error-code>500</error-code>
+    <location>/WEB-INF/view/error/redirect.jsp?type=systemError</location>
   </error-page>
   </error-page>
 </web-app>
 </web-app>