Single sign on 华夫:如何强制kerberos?

Single sign on 华夫:如何强制kerberos?,single-sign-on,kerberos,ntlm,waffle,Single Sign On,Kerberos,Ntlm,Waffle,我正在使用for SingleSignOn连接到Web应用程序。它工作正常,但我想知道是否有可能强制Kerberos避免回退到NTLM。更新(04.04.18): HTTP身份验证不支持“Kerberos”,因此无法强制执行。 Http只知道“协商”。如果在windows下使用协商,您将获得一个SPNEGO令牌,它可以是Kerberos或NTLM 我将华夫饼设置更改为使用自定义NegotiateSecurityFilterProvider。这基本上是NegotiateSecurityFilter

我正在使用for SingleSignOn连接到Web应用程序。它工作正常,但我想知道是否有可能强制Kerberos避免回退到NTLM。

更新(04.04.18): HTTP身份验证不支持“Kerberos”,因此无法强制执行。 Http只知道“协商”。如果在windows下使用协商,您将获得一个SPNEGO令牌,它可以是Kerberos或NTLM

我将华夫饼设置更改为使用自定义NegotiateSecurityFilterProvider。这基本上是NegotiateSecurityFilterProvider类,但有三个变化。这样,服务将只接受Kerberos令牌作为身份验证。一个肮脏的解决方案,但它可以工作(尚未使用Kerberos进行测试):

  • 建造商(仅接受协商):

  • 在doFilter方法中,我添加了以下内容:

    //Custom NTLM Token Disable
    if(isNTLMToken(authorizationHeader)) {
        response.setHeader("Connection", "keep-alive");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.flushBuffer();
        return null;
    }
    
  • 添加了一个isNTLMToken方法:

    private boolean isNTLMToken(AuthorizationHeader authorizationHeader) {
        String decodedToken = new String(Base64.getDecoder().decode(authorizationHeader.getToken()));
        return decodedToken.contains("NTLM")
            || decodedToken.contains("ntlm");
    }
    
  • 这将是整个班级:

    /**
     * Waffle (https://github.com/Waffle/waffle)
     *
     * Copyright (c) 2010-2016 Application Security, Inc.
     *
     * All rights reserved. This program and the accompanying materials are made available     under the terms of the Eclipse
     * Public License v1.0 which accompanies this distribution, and is available at
     * https://www.eclipse.org/legal/epl-v10.html.
     *
     * Contributors: Application Security, Inc.
     */
    package com.example.extention;
    
    import java.io.IOException;
    import java.security.InvalidParameterException;
    import java.util.ArrayList;
    import java.util.Base64;
    import java.util.Iterator;
    import java.util.List;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.google.common.io.BaseEncoding;
    
    import waffle.servlet.spi.SecurityFilterProvider;
    import waffle.util.AuthorizationHeader;
    import waffle.util.NtlmServletRequest;
    import waffle.windows.auth.IWindowsAuthProvider;
    import waffle.windows.auth.IWindowsIdentity;
    import waffle.windows.auth.IWindowsSecurityContext;
    
    /**
     * A negotiate security filter provider.
     *
     * @author dblock[at]dblock[dot]org
     */
    public class CustomSecurityFilter implements SecurityFilterProvider {
    
        /** The Constant LOGGER. */
        private static final Logger LOGGER = LoggerFactory.getLogger(CustomSecurityFilter.class);
    
        /** The Constant WWW_AUTHENTICATE. */
        private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
    
        /** The Constant PROTOCOLS. */
        private static final String PROTOCOLS = "protocols";
    
        /** The Constant NEGOTIATE. */
        private static final String NEGOTIATE = "Negotiate";
    
        /** The protocols. */
        private List<String> protocols = new ArrayList<>();
    
        /** The auth. */
        private final IWindowsAuthProvider auth;
    
        /**
         * Instantiates a new negotiate security filter provider.
         *
         * @param newAuthProvider the new auth provider
         */
        public CustomSecurityFilter(final IWindowsAuthProvider newAuthProvider) {
            this.auth = newAuthProvider;
            this.protocols.add(CustomSecurityFilter.NEGOTIATE);
        }
    
        /**
         * Gets the protocols.
         *
         * @return the protocols
         */
        public List<String> getProtocols() {
            return this.protocols;
        }
    
        /**
         * Sets the protocols.
         *
         * @param values the new protocols
         */
        public void setProtocols(final List<String> values) {
            this.protocols = values;
        }
    
        /*
         * (non-Javadoc)
         *
         * @see
         * waffle.servlet.spi.SecurityFilterProvider#sendUnauthorized(javax.servlet.http
         * .HttpServletResponse)
         */
        @Override
        public void sendUnauthorized(final HttpServletResponse response) {
            final Iterator<String> protocolsIterator = this.protocols.iterator();
            while (protocolsIterator.hasNext()) {
                response.addHeader(WWW_AUTHENTICATE, protocolsIterator.next());
            }
        }
    
        /*
         * (non-Javadoc)
         *
         * @see
         * waffle.servlet.spi.SecurityFilterProvider#isPrincipalException(javax.servlet.
         * http.HttpServletRequest)
         */
        @Override
        public boolean isPrincipalException(final HttpServletRequest request) {
            final AuthorizationHeader authorizationHeader = new AuthorizationHeader(request);
            final boolean ntlmPost = authorizationHeader.isNtlmType1PostAuthorizationHeader();
            LOGGER.debug("authorization: {}, ntlm post: {}", authorizationHeader, Boolean.valueOf(ntlmPost));
            return ntlmPost;
        }
    
        /*
         * (non-Javadoc)
         *
         * @see waffle.servlet.spi.SecurityFilterProvider#doFilter(javax.servlet.http.
         * HttpServletRequest, javax.servlet.http.HttpServletResponse)
         */
        @Override
        public IWindowsIdentity doFilter(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
    
            final AuthorizationHeader authorizationHeader = new AuthorizationHeader(request);
            final boolean ntlmPost = authorizationHeader.isNtlmType1PostAuthorizationHeader();
    
    
            //Custom NTLM Token Disable
            if(isNTLMToken(authorizationHeader)) {
                response.setHeader("Connection", "keep-alive");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.flushBuffer();
                return null;
            }
    
            // maintain a connection-based session for NTLM tokens
            final String connectionId = NtlmServletRequest.getConnectionId(request);
            final String securityPackage = authorizationHeader.getSecurityPackage();
            LOGGER.debug("security package: {}, connection id: {}", securityPackage, connectionId);
    
            if (ntlmPost) {
                // type 2 NTLM authentication message received
                this.auth.resetSecurityToken(connectionId);
            }
    
            final byte[] tokenBuffer = authorizationHeader.getTokenBytes();
            LOGGER.debug("token buffer: {} byte(s)", Integer.valueOf(tokenBuffer.length));
            final IWindowsSecurityContext securityContext = this.auth.acceptSecurityToken(connectionId, tokenBuffer, securityPackage);
    
            final byte[] continueTokenBytes = securityContext.getToken();
            if (continueTokenBytes != null && continueTokenBytes.length > 0) {
                final String continueToken = BaseEncoding.base64().encode(continueTokenBytes);
                LOGGER.debug("continue token: {}", continueToken);
                response.addHeader(WWW_AUTHENTICATE, securityPackage + " " + continueToken);
            }
    
            LOGGER.debug("continue required: {}", Boolean.valueOf(securityContext.isContinue()));
            if (securityContext.isContinue() || ntlmPost) {
                response.setHeader("Connection", "keep-alive");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.flushBuffer();
                return null;
            }
    
            final IWindowsIdentity identity = securityContext.getIdentity();
            securityContext.dispose();
            return identity;
        }
    
        private boolean isNTLMToken(AuthorizationHeader authorizationHeader) {
            String decodedToken = new String(Base64.getDecoder().decode(authorizationHeader.getToken()));
            return decodedToken.contains("NTLM")
                    || decodedToken.contains("ntlm");
        }
    
        /*
         * (non-Javadoc)
         *
         * @see
         * waffle.servlet.spi.SecurityFilterProvider#isSecurityPackageSupported(java.
         * lang.String)
         */
        @Override
        public boolean isSecurityPackageSupported(final String securityPackage) {
            for (final String protocol : this.protocols) {
                if (protocol.equalsIgnoreCase(securityPackage)) {
                    return true;
                }
            }
            return false;
        }
    
        /*
         * (non-Javadoc)
         *
         * @see
         * waffle.servlet.spi.SecurityFilterProvider#initParameter(java.lang.String,
         * java.lang.String)
         */
        @Override
        public void initParameter(final String parameterName, final String parameterValue) {
            if (parameterName.equals(PROTOCOLS)) {
                this.protocols = new ArrayList<>();
                final String[] protocolNames = parameterValue.split("\\s+");
                for (String protocolName : protocolNames) {
                    protocolName = protocolName.trim();
                    if (protocolName.length() > 0) {
                        LOGGER.debug("init protocol: {}", protocolName);
                        if (protocolName.equals(NEGOTIATE)) {
                            this.protocols.add(protocolName);
                        } else {
                            LOGGER.error("unsupported protocol: {}", protocolName);
                            throw new RuntimeException("Unsupported protocol: " + protocolName);
                        }
                    }
                }
            } else {
                throw new InvalidParameterException(parameterName);
            }
        }
    }
    
    /**
    *华夫饼干(https://github.com/Waffle/waffle)
    *
    *版权所有(c)2010-2016应用安全公司。
    *
    *版权所有。本计划和随附材料在Eclipse条款下提供
    *此发行版附带的公共许可证v1.0,可在
    * https://www.eclipse.org/legal/epl-v10.html.
    *
    *贡献者:应用程序安全公司。
    */
    包com.example.extension;
    导入java.io.IOException;
    导入java.security.InvalidParameterException;
    导入java.util.ArrayList;
    导入java.util.Base64;
    导入java.util.Iterator;
    导入java.util.List;
    导入javax.servlet.http.HttpServletRequest;
    导入javax.servlet.http.HttpServletResponse;
    导入org.slf4j.Logger;
    导入org.slf4j.LoggerFactory;
    导入com.google.common.io.BaseEncoding;
    导入waffle.servlet.spi.SecurityFilterProvider;
    导入waffle.util.AuthorizationHeader;
    导入waffle.util.NtlmServletRequest;
    导入waffle.windows.auth.IWindowsAuthProvider;
    导入waffle.windows.auth.IWindowsIdentity;
    导入waffle.windows.auth.IWindowsSecurityContext;
    /**
    *协商安全筛选器提供程序。
    *
    *@author dblock[at]dblock[dot]org
    */
    公共类CustomSecurityFilter实现SecurityFilterProvider{
    /**常数记录器*/
    私有静态最终记录器Logger=LoggerFactory.getLogger(CustomSecurityFilter.class);
    /**常数WWW_验证*/
    私有静态最终字符串WWW\u AUTHENTICATE=“WWW AUTHENTICATE”;
    /**不变的协议*/
    专用静态最终字符串协议=“协议”;
    /**不断的谈判*/
    私有静态最终字符串NEGOTIATE=“NEGOTIATE”;
    /**协议*/
    私有列表协议=新的ArrayList();
    /**作者*/
    私有最终iwindowsauth提供者身份验证;
    /**
    *实例化新的协商安全筛选器提供程序。
    *
    *@param newAuthProvider新的身份验证提供程序
    */
    public CustomSecurityFilter(最终IWindowsAuthProvider newAuthProvider){
    this.auth=newAuthProvider;
    this.protocols.add(CustomSecurityFilter.NEGOTIATE);
    }
    /**
    *获取协议。
    *
    *@返回协议
    */
    公共列表getProtocols(){
    将此文件返回。协议;
    }
    /**
    *设置协议。
    *
    *@param重视新协议
    */
    公共协议(最终列表值){
    此参数=值;
    }
    /*
    *(非Javadoc)
    *
    *@见
    *waffle.servlet.spi.SecurityFilterProvider#sendUnauthorized(javax.servlet.http
    *.HttpServletResponse)
    */
    @凌驾
    public void sendUnauthorized(最终HttpServletResponse){
    final Iterator protocolsIterator=this.protocols.Iterator();
    while(protocolsIterator.hasNext()){
    addHeader(WWW_AUTHENTICATE,protocolsIterator.next());
    }
    }
    /*
    *(非Javadoc)
    *
    *@见
    *SecurityFilterProvider#isPrincipalException(javax.servlet)。
    *http.HttpServletRequest)
    */
    @凌驾
    公共布尔isPrincipalException(最终HttpServletRequest请求){
    最终授权标头AuthorizationHeader=新授权标头(请求);
    最终布尔值ntlmPost=authorizationHeader.isNtlmType1PostAuthorizationHeader();
    debug(“authorization:{},ntlmPost:{}”,authorizationHeader,Boolean.valueOf(ntlmPost));
    返回ntlmPost;
    }
    /*
    *(非Javadoc)
    *
    *@请参阅waffle.servlet.spi.SecurityFilterProvider#doFilter(javax.servlet.http。
    *HttpServletRequest,javax.servlet.http.HttpServletResponse)
    */
    @凌驾
    公共IWindowsIdentity doFilter(最终HttpServletRequest请求,最终HttpServletResponse响应)引发IOException{
    最终授权标头AuthorizationHeader=新授权标头(请求);
    最终布尔值ntlmPost=authorizationHeader.isNtlmType1PostAuthorizationHeader();
    //自定义NTLM令牌禁用
    if(isNTLMToken(授权标头)){
    setHeader(“连接”,“保持活动”);
    response.setStatus(HttpServletResponse.SC_未经授权);
    response.flushBuffer();
    返回null;
    }
    //为NTLM令牌维护基于连接的会话
    最终字符串connectionId=NtlmServletRequest.getConnectionId(请求);
    最后一个字符串securityPackage=authorizationHeader.getSecurityPackage();
    debug(“安全包:{},连接id:{}”,securityPackage,connectionId);
    国际单项体育联合会(ntlmPost){
    //接收到类型2 NTLM身份验证消息
    this.auth.resetSecurityToken(connectionId);
    }
    最后一个字节[]tokenBuffer=authorizationHeader.getTokenBytes();
    debug(“令牌缓冲区:{}字节)”,Integer.valueOf(tokenBuffer.length));
    final IWindowsSecurityContext securityContext=this.auth.acceptSecurityToken(connectionId、tokenBuffer、securityPackage);
    
    /**
     * Waffle (https://github.com/Waffle/waffle)
     *
     * Copyright (c) 2010-2016 Application Security, Inc.
     *
     * All rights reserved. This program and the accompanying materials are made available     under the terms of the Eclipse
     * Public License v1.0 which accompanies this distribution, and is available at
     * https://www.eclipse.org/legal/epl-v10.html.
     *
     * Contributors: Application Security, Inc.
     */
    package com.example.extention;
    
    import java.io.IOException;
    import java.security.InvalidParameterException;
    import java.util.ArrayList;
    import java.util.Base64;
    import java.util.Iterator;
    import java.util.List;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.google.common.io.BaseEncoding;
    
    import waffle.servlet.spi.SecurityFilterProvider;
    import waffle.util.AuthorizationHeader;
    import waffle.util.NtlmServletRequest;
    import waffle.windows.auth.IWindowsAuthProvider;
    import waffle.windows.auth.IWindowsIdentity;
    import waffle.windows.auth.IWindowsSecurityContext;
    
    /**
     * A negotiate security filter provider.
     *
     * @author dblock[at]dblock[dot]org
     */
    public class CustomSecurityFilter implements SecurityFilterProvider {
    
        /** The Constant LOGGER. */
        private static final Logger LOGGER = LoggerFactory.getLogger(CustomSecurityFilter.class);
    
        /** The Constant WWW_AUTHENTICATE. */
        private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
    
        /** The Constant PROTOCOLS. */
        private static final String PROTOCOLS = "protocols";
    
        /** The Constant NEGOTIATE. */
        private static final String NEGOTIATE = "Negotiate";
    
        /** The protocols. */
        private List<String> protocols = new ArrayList<>();
    
        /** The auth. */
        private final IWindowsAuthProvider auth;
    
        /**
         * Instantiates a new negotiate security filter provider.
         *
         * @param newAuthProvider the new auth provider
         */
        public CustomSecurityFilter(final IWindowsAuthProvider newAuthProvider) {
            this.auth = newAuthProvider;
            this.protocols.add(CustomSecurityFilter.NEGOTIATE);
        }
    
        /**
         * Gets the protocols.
         *
         * @return the protocols
         */
        public List<String> getProtocols() {
            return this.protocols;
        }
    
        /**
         * Sets the protocols.
         *
         * @param values the new protocols
         */
        public void setProtocols(final List<String> values) {
            this.protocols = values;
        }
    
        /*
         * (non-Javadoc)
         *
         * @see
         * waffle.servlet.spi.SecurityFilterProvider#sendUnauthorized(javax.servlet.http
         * .HttpServletResponse)
         */
        @Override
        public void sendUnauthorized(final HttpServletResponse response) {
            final Iterator<String> protocolsIterator = this.protocols.iterator();
            while (protocolsIterator.hasNext()) {
                response.addHeader(WWW_AUTHENTICATE, protocolsIterator.next());
            }
        }
    
        /*
         * (non-Javadoc)
         *
         * @see
         * waffle.servlet.spi.SecurityFilterProvider#isPrincipalException(javax.servlet.
         * http.HttpServletRequest)
         */
        @Override
        public boolean isPrincipalException(final HttpServletRequest request) {
            final AuthorizationHeader authorizationHeader = new AuthorizationHeader(request);
            final boolean ntlmPost = authorizationHeader.isNtlmType1PostAuthorizationHeader();
            LOGGER.debug("authorization: {}, ntlm post: {}", authorizationHeader, Boolean.valueOf(ntlmPost));
            return ntlmPost;
        }
    
        /*
         * (non-Javadoc)
         *
         * @see waffle.servlet.spi.SecurityFilterProvider#doFilter(javax.servlet.http.
         * HttpServletRequest, javax.servlet.http.HttpServletResponse)
         */
        @Override
        public IWindowsIdentity doFilter(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
    
            final AuthorizationHeader authorizationHeader = new AuthorizationHeader(request);
            final boolean ntlmPost = authorizationHeader.isNtlmType1PostAuthorizationHeader();
    
    
            //Custom NTLM Token Disable
            if(isNTLMToken(authorizationHeader)) {
                response.setHeader("Connection", "keep-alive");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.flushBuffer();
                return null;
            }
    
            // maintain a connection-based session for NTLM tokens
            final String connectionId = NtlmServletRequest.getConnectionId(request);
            final String securityPackage = authorizationHeader.getSecurityPackage();
            LOGGER.debug("security package: {}, connection id: {}", securityPackage, connectionId);
    
            if (ntlmPost) {
                // type 2 NTLM authentication message received
                this.auth.resetSecurityToken(connectionId);
            }
    
            final byte[] tokenBuffer = authorizationHeader.getTokenBytes();
            LOGGER.debug("token buffer: {} byte(s)", Integer.valueOf(tokenBuffer.length));
            final IWindowsSecurityContext securityContext = this.auth.acceptSecurityToken(connectionId, tokenBuffer, securityPackage);
    
            final byte[] continueTokenBytes = securityContext.getToken();
            if (continueTokenBytes != null && continueTokenBytes.length > 0) {
                final String continueToken = BaseEncoding.base64().encode(continueTokenBytes);
                LOGGER.debug("continue token: {}", continueToken);
                response.addHeader(WWW_AUTHENTICATE, securityPackage + " " + continueToken);
            }
    
            LOGGER.debug("continue required: {}", Boolean.valueOf(securityContext.isContinue()));
            if (securityContext.isContinue() || ntlmPost) {
                response.setHeader("Connection", "keep-alive");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.flushBuffer();
                return null;
            }
    
            final IWindowsIdentity identity = securityContext.getIdentity();
            securityContext.dispose();
            return identity;
        }
    
        private boolean isNTLMToken(AuthorizationHeader authorizationHeader) {
            String decodedToken = new String(Base64.getDecoder().decode(authorizationHeader.getToken()));
            return decodedToken.contains("NTLM")
                    || decodedToken.contains("ntlm");
        }
    
        /*
         * (non-Javadoc)
         *
         * @see
         * waffle.servlet.spi.SecurityFilterProvider#isSecurityPackageSupported(java.
         * lang.String)
         */
        @Override
        public boolean isSecurityPackageSupported(final String securityPackage) {
            for (final String protocol : this.protocols) {
                if (protocol.equalsIgnoreCase(securityPackage)) {
                    return true;
                }
            }
            return false;
        }
    
        /*
         * (non-Javadoc)
         *
         * @see
         * waffle.servlet.spi.SecurityFilterProvider#initParameter(java.lang.String,
         * java.lang.String)
         */
        @Override
        public void initParameter(final String parameterName, final String parameterValue) {
            if (parameterName.equals(PROTOCOLS)) {
                this.protocols = new ArrayList<>();
                final String[] protocolNames = parameterValue.split("\\s+");
                for (String protocolName : protocolNames) {
                    protocolName = protocolName.trim();
                    if (protocolName.length() > 0) {
                        LOGGER.debug("init protocol: {}", protocolName);
                        if (protocolName.equals(NEGOTIATE)) {
                            this.protocols.add(protocolName);
                        } else {
                            LOGGER.error("unsupported protocol: {}", protocolName);
                            throw new RuntimeException("Unsupported protocol: " + protocolName);
                        }
                    }
                }
            } else {
                throw new InvalidParameterException(parameterName);
            }
        }
    }