Single sign on 华夫:如何强制kerberos?
我正在使用for SingleSignOn连接到Web应用程序。它工作正常,但我想知道是否有可能强制Kerberos避免回退到NTLM。更新(04.04.18): HTTP身份验证不支持“Kerberos”,因此无法强制执行。 Http只知道“协商”。如果在windows下使用协商,您将获得一个SPNEGO令牌,它可以是Kerberos或NTLM 我将华夫饼设置更改为使用自定义NegotiateSecurityFilterProvider。这基本上是NegotiateSecurityFilterProvider类,但有三个变化。这样,服务将只接受Kerberos令牌作为身份验证。一个肮脏的解决方案,但它可以工作(尚未使用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
//Custom NTLM Token Disable
if(isNTLMToken(authorizationHeader)) {
response.setHeader("Connection", "keep-alive");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.flushBuffer();
return null;
}
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);
}
}
}