简体   繁体   English

Tomcat:单个Web应用程序有多种身份验证方案吗?

[英]Tomcat: Multiple authentication schemes for a single web application?

My web application uses internal web API (simple AJAX requests from a browser as it's the major client) that's eventually supposed to be exposed externally for the 3rd parties. 我的Web应用程序使用内部Web API(作为主要客户端,从浏览器发出的简单AJAX请求),最终应该在外部为第三方公开。 Since the API is and must be protected with the security constraints in web.xml , a user or a client must be authenticated. 由于该API已且必须受到web.xml的安全性约束的保护,因此必须对用户或客户端进行身份验证。 Currently, there's a custom form authenticator implemented, it performs some additional checks and actions, and then simply delegates the further authentication processing to the FormAuthenticator class the custom authenticator is derived from. 当前,实现了一个自定义表单身份验证器,它执行一些其他检查和操作,然后将进一步的身份验证处理委托给派生自定义身份验证器的FormAuthenticator类。 This works really nice yet, because a user is simply forced to login and pass authentication, and the only client is a web browser. 这样做确实非常不错,因为用户只是被迫登录并通过身份验证,而唯一的客户端是Web浏览器。

But FORM authentication is not very suitable for another kinds of clients: let's say an Android client, various 3rd-party clients, etc. Too pass the form authentication they all must simulate the behavior I was looking for in this question: How can I simulate form authentication in Tomcat using JMeter? 但是FORM身份验证不适用于其他类型的客户端:例如Android客户端,各种第三方客户端等。太过了表单身份验证,它们都必须模拟我在此问题中寻找的行为: 如何模拟JMeter在Tomcat中进行表单身份验证? . After some investigation of the Tomcat source code, I've got an idea that it should be possible to extend the AuthenticatorBase class to implement own way of authentication (like FormAuthenticator or BasicAuthenticator.java do). 在对Tomcat源代码进行了一些研究之后,我想到了应该可以扩展AuthenticatorBase类以实现自己的身份验证方式(例如FormAuthenticatorBasicAuthenticator.java这样做)。 What I tried to do was: 我试图做的是:

public final class SimpleAuthenticator extends AuthenticatorBase {

    private static final String USERNAME_PARAMETER = "username";
    private static final String PASSWORD_PARAMETER = "password";

    @Override
    protected boolean authenticate(Request request, Response response, LoginConfig config) throws IOException {
        final Principal principal = request.getUserPrincipal();
        final String ssoId = (String) request.getNote(REQ_SSOID_NOTE);
        if ( principal != null ) {
            if ( ssoId != null ) {
                associate(ssoId, request.getSessionInternal(true));
            }
            return true;
        }
        if ( ssoId != null && reauthenticateFromSSO(ssoId, request) ) {
            return true;
        }
        final String contextPath = request.getContextPath();
        final String requestURI = request.getDecodedRequestURI();
        final boolean login = requestURI.equals(contextPath + "/authenticate");
        if ( !login ) {
            response.sendError(SC_FORBIDDEN);
            return false;
        }
        final String username = request.getParameter(USERNAME_PARAMETER);
        final String password = request.getParameter(PASSWORD_PARAMETER);
        final Realm realm = context.getRealm();
        final Principal authenticatedUserPrincipal = realm.authenticate(username, password);
        if ( authenticatedUserPrincipal == null ) {
            response.sendError(SC_UNAUTHORIZED);
            return false;
        }
        register(request, response, authenticatedUserPrincipal, "SIMPLE", username, password);
        return true;
    }

}

Simply speaking, I'd like to use something like /%CONTEXT_PATH%/authenticate?username=%USERNAME%&password=%PASSWORD% to authenticate a user with my custom non-form SimpleAuthenticator . 简而言之,我想使用/%CONTEXT_PATH%/authenticate?username=%USERNAME%&password=%PASSWORD%来通过我的自定义非格式SimpleAuthenticator验证用户。 Not really sure if BasicAuthentication would be better for such a case, but I got the following issues with the example above: 不太确定BasicAuthentication是否适合这种情况,但是上面的示例出现了以下问题:

  • Tomcat allows to specify multiple Valve 's in context.xml . Tomcat允许在context.xml指定多个Valve If the another authenticator is added to the context.xml file, then every secured resource is processed with every authenticator. 如果将另一个验证者添加到context.xml文件,则每个验证者都将处理每个安全资源。 (In principle, I understand why it happens, but can they be separated for different resources?) (原则上,我理解为什么会发生这种情况,但是可以将它们分开以使用不同的资源吗?)
  • /%CONTEXT_PATH%/authenticate is not accessible (HTTP 404). /%CONTEXT_PATH%/authenticate无法访问(HTTP 404)。 (Not clear yet knowing that /j_security_check is simulated somehow.) (尚不清楚/j_security_check是通过某种方式模拟的。)
  • I couldn't find a way to specify multiple authentication schemes in Tomcat, so "old" web browser client could still use FormAuthenticator (like it does today), but the "light-weight" clients could use that simplified authentication I tried to implement with SimpleAuthenticator . 我找不到在Tomcat中指定多种身份验证方案的方法,因此“旧的” Web浏览器客户端仍可以使用FormAuthenticator (就像今天一样),但是“轻量级”的客户端可以使用我尝试实现的简化身份验证与SimpleAuthenticator (Don't even know if it's possible -- that is the core) (甚至不知道是否有可能-这就是核心)
  • As far as I understood the servlet specification, only one login-config is allowed for entire web-application. 据我了解的servlet规范,整个Web应用程序只允许一个login-config (Well, should I have use another web app to provide the API?) (嗯,我应该使用另一个Web应用程序来提供API吗?)
  • I saw some mentions to implement custom authentication via Filter , but if it's possible -- I'd like to keep the authenticator module separately in a single place (like it already is and confirmed with Tomcat: Custom form authenicator in a web application, not as a stand-alone JAR module. Possible? ). 我看到了一些提到通过Filter实现自定义身份验证的内容,但是,如果可能的话,我想将身份验证器模块放在一个单独的位置(就像已经存在并通过Tomcat确认一样) :Web应用程序中的自定义表单身份验证器,而不是作为独立的JAR模块。可能吗? )。 However I'm very ok to review the general concept I use from scratch. 但是,我可以从头开始回顾一下我使用的一般概念。

I suspect that I'm doing a quite wrong thing and have total understanding, but I don't believe that there's no way to implement multiple authentication schemes in Tomcat. 我怀疑我做错了一件事情并且已经完全了解了,但是我不相信无法在Tomcat中实现多种身份验证方案。

Is there any way to provide multiple authentication schemes to extract the authentication out of FormAuthetication (for light-weight clients)? 有什么方法可以提供多种身份验证方案,以从FormAuthetication提取身份验证(对于轻量级客户端)? Your help would be really very appreciated. 非常感谢您的帮助。 Thanks in advance. 提前致谢。

The bottom line: You cannot configure multiple authentication schemes for the same web application in Tomcat. 最重要的是:您不能为Tomcat中的同一Web应用程序配置多个身份验证方案。 You configure one auth-method that will be used for the authentication in the web.xml : 您可以在web.xml配置一种用于身份验证的身份验证方法:

<login-config>
    <auth-method>CLIENT-CERT</auth-method>
</login-config>

Tomcat map on the authenticator for the web application authentication. Tomcat映射到用于Web应用程序身份验证的身份验证器。 For example, for the CLIENT-CERT it will use org.apache.catalina.authenticator.SSLAuthenticator The mapping is in the file org/apache/catalina/startup/Authenticators.properties 例如,对于CLIENT-CERT ,它将使用org.apache.catalina.authenticator.SSLAuthenticator映射位于文件org/apache/catalina/startup/Authenticators.properties

For purpose you describe in the question you may use regular Tomcat Form Authenticator ( <auth-method>FORM</auth-method> ) 为此,您可以在问题中描述您可以使用常规的Tomcat Form Authenticator( <auth-method>FORM</auth-method>

The following code will authenticate a user: 以下代码将对用户进行身份验证:

String url = "j_security_check?j_username=" + username + "&j_password=" + password;
String redirectUrl = response.encodeRedirectURL(url);
response.sendRedirect(redirectUrl);

When you first access application authenticate a user by execution URL above. 首次访问应用程序时,请通过上面的执行URL对用户进行身份验证。 Also, you can use Form Authenticator for “old” code :) Please note, the code above uses GET method. 另外,您可以将Form Authenticator用于“旧”代码:)请注意,以上代码使用GET方法。 I recommend to submit same parameters in POST method to j_security_check (you can do it in AJAX). 我建议在POST方法中向j_security_check提交相同的参数(可以在AJAX中完成)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM