未验证 提交 9891f4b6 编写于 作者: sinat_25235033's avatar sinat_25235033 提交者: GitHub

fix auth permission bypass due to special request uri path (#168)

* fix auth permission bypass due to special request uri path

* fix auth permission bypass due to special request uri path
上级 12987a72
......@@ -3,6 +3,7 @@ package com.usthe.sureness.subject.creater;
import com.usthe.sureness.subject.Subject;
import com.usthe.sureness.subject.SubjectCreate;
import com.usthe.sureness.subject.support.PasswordSubject;
import com.usthe.sureness.util.ServletUtil;
import com.usthe.sureness.util.SurenessConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -64,7 +65,7 @@ public class BasicSubjectServletCreator implements SubjectCreate {
username = username.trim();
String password = auth[1] == null ? null : auth[1].trim();
String remoteHost = ((HttpServletRequest) context).getRemoteHost();
String requestUri = ((HttpServletRequest) context).getRequestURI();
String requestUri = ServletUtil.getRequestUri((HttpServletRequest) context);
String requestType = ((HttpServletRequest) context).getMethod();
String targetUri = requestUri.concat("===").concat(requestType).toLowerCase();
return PasswordSubject.builder(username, password)
......
......@@ -3,6 +3,7 @@ package com.usthe.sureness.subject.creater;
import com.usthe.sureness.subject.Subject;
import com.usthe.sureness.subject.SubjectCreate;
import com.usthe.sureness.subject.support.DigestSubject;
import com.usthe.sureness.util.ServletUtil;
import com.usthe.sureness.util.SurenessConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -77,7 +78,7 @@ public class DigestSubjectServletCreator implements SubjectCreate {
return null;
}
String remoteHost = ((HttpServletRequest) context).getRemoteHost();
String requestUri = ((HttpServletRequest) context).getRequestURI();
String requestUri = ServletUtil.getRequestUri((HttpServletRequest) context);
String requestType = ((HttpServletRequest) context).getMethod();
String targetUri = requestUri.concat("===").concat(requestType).toLowerCase();
return DigestSubject.builder(username, response)
......
......@@ -4,6 +4,7 @@ import com.usthe.sureness.subject.Subject;
import com.usthe.sureness.subject.SubjectCreate;
import com.usthe.sureness.subject.support.JwtSubject;
import com.usthe.sureness.util.JsonWebTokenUtil;
import com.usthe.sureness.util.ServletUtil;
import com.usthe.sureness.util.SurenessConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -47,7 +48,7 @@ public class JwtSubjectServletCreator implements SubjectCreate {
return null;
}
String remoteHost = ((HttpServletRequest) context).getRemoteHost();
String requestUri = ((HttpServletRequest) context).getRequestURI();
String requestUri = ServletUtil.getRequestUri((HttpServletRequest) context);
String requestType = ((HttpServletRequest) context).getMethod();
String targetUri = requestUri.concat("===").concat(requestType.toLowerCase());
return JwtSubject.builder(jwtValue)
......
......@@ -4,6 +4,7 @@ import com.usthe.sureness.subject.Subject;
import com.usthe.sureness.subject.SubjectCreate;
import com.usthe.sureness.subject.support.JwtSubject;
import com.usthe.sureness.util.JsonWebTokenUtil;
import com.usthe.sureness.util.ServletUtil;
import com.usthe.sureness.util.SurenessConstant;
import javax.servlet.http.HttpServletRequest;
......@@ -35,7 +36,7 @@ public class JwtSubjectWsServletCreator implements SubjectCreate {
if (jwtToken != null) {
jwtToken = jwtToken.trim();
String remoteHost = ((HttpServletRequest) context).getRemoteHost();
String requestUri = ((HttpServletRequest) context).getRequestURI();
String requestUri = ServletUtil.getRequestUri((HttpServletRequest) context);
String requestType = ((HttpServletRequest) context).getMethod();
String targetUri = requestUri.concat("===").concat(requestType.toLowerCase());
return JwtSubject.builder(jwtToken)
......
......@@ -3,6 +3,7 @@ package com.usthe.sureness.subject.creater;
import com.usthe.sureness.subject.Subject;
import com.usthe.sureness.subject.SubjectCreate;
import com.usthe.sureness.subject.support.NoneSubject;
import com.usthe.sureness.util.ServletUtil;
import javax.servlet.http.HttpServletRequest;
......@@ -22,7 +23,7 @@ public class NoneSubjectServletCreator implements SubjectCreate {
@Override
public Subject createSubject(Object context) {
String remoteHost = ((HttpServletRequest) context).getRemoteHost();
String requestUri = ((HttpServletRequest) context).getRequestURI();
String requestUri = ServletUtil.getRequestUri((HttpServletRequest) context);
String requestType = ((HttpServletRequest) context).getMethod();
String targetUri = requestUri.concat("===").concat(requestType).toLowerCase();
return NoneSubject.builder().setRemoteHost(remoteHost)
......
......@@ -38,7 +38,7 @@ public class JsonWebTokenUtil {
/** Encryption and decryption signature **/
private static Key secretKey;
private static boolean isUsedDefault = true;
private static volatile boolean isUsedDefault = true;
static {
byte[] secretKeyBytes = DatatypeConverter.parseBase64Binary(DEFAULT_SECRET_KEY);
......
package com.usthe.sureness.util;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
/**
* util for servlet container
* from apache shiro
* @author shiro
* @date 2022/10/23 15:19
*/
public class ServletUtil {
private static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
public static String getRequestUri(HttpServletRequest request) {
String uri = valueOrEmpty(request.getContextPath()) + "/" +
valueOrEmpty(request.getServletPath()) +
valueOrEmpty(request.getPathInfo());
return normalize(decodeAndCleanUriString(request, uri));
}
public static String valueOrEmpty(String value) {
if (value == null) {
return "";
}
return value;
}
private static String decodeAndCleanUriString(HttpServletRequest request, String uri) {
uri = decodeRequestString(request, uri);
return removeSemicolon(uri);
}
private static String removeSemicolon(String uri) {
int semicolonIndex = uri.indexOf(';');
return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri);
}
public static String decodeRequestString(HttpServletRequest request, String source) {
String enc = determineEncoding(request);
try {
return URLDecoder.decode(source, enc);
} catch (UnsupportedEncodingException ex) {
return URLDecoder.decode(source);
}
}
protected static String determineEncoding(HttpServletRequest request) {
String enc = request.getCharacterEncoding();
if (enc == null) {
enc = DEFAULT_CHARACTER_ENCODING;
}
return enc;
}
private static String normalize(String path) {
if (path == null) {
return null;
}
// Create a place for the normalized path
String normalized = path;
if (normalized.indexOf('\\') >= 0) {
normalized = normalized.replace('\\', '/');
}
if ("/.".equals(normalized)) {
return "/";
}
// Add a leading "/" if necessary
if (!normalized.startsWith("/")) {
normalized = "/" + normalized;
}
// Resolve occurrences of "//" in the normalized path
while (true) {
int index = normalized.indexOf("//");
if (index < 0) {
break;
}
normalized = normalized.substring(0, index) +
normalized.substring(index + 1);
}
// Resolve occurrences of "/./" in the normalized path
while (true) {
int index = normalized.indexOf("/./");
if (index < 0) {
break;
}
normalized = normalized.substring(0, index) +
normalized.substring(index + 2);
}
// Resolve occurrences of "/../" in the normalized path
while (true) {
int index = normalized.indexOf("/../");
if (index < 0) {
break;
}
if (index == 0) {
return (null);
}
int index2 = normalized.lastIndexOf('/', index - 1);
normalized = normalized.substring(0, index2) +
normalized.substring(index + 3);
}
// Return the normalized path that we have completed
return (normalized);
}
}
......@@ -25,4 +25,6 @@ public class SurenessConstant {
public static final String TOKEN = "token";
/** JWT auth **/
public static final String JWT = "Jwt";
/** Url special char ; **/
public static final String URL_PATH_SPECIAL = ";";
}
......@@ -82,19 +82,19 @@ public class DefaultPathRoleMatcherTest {
public void isExcludedResource() {
loadExcludedResource();
HttpServletRequest request = createNiceMock(HttpServletRequest.class);
expect(request.getRequestURI()).andReturn("/api/v2/detail");
expect(request.getServletPath()).andReturn("/api/v2/detail");
expect(request.getMethod()).andReturn("put");
replay(request);
Subject subject = NoneSubject.builder().setTargetUri(request.getRequestURI().concat("===")
Subject subject = NoneSubject.builder().setTargetUri(request.getServletPath().concat("===")
.concat(request.getMethod()).toLowerCase()).build();
assertTrue(pathRoleMatcher.isExcludedResource(subject));
verify(request);
request = createNiceMock(HttpServletRequest.class);
expect(request.getRequestURI()).andReturn("/book/v2/detail");
expect(request.getServletPath()).andReturn("/book/v2/detail");
expect(request.getMethod()).andReturn("put");
replay(request);
subject = NoneSubject.builder().setTargetUri(request.getRequestURI().concat("===")
subject = NoneSubject.builder().setTargetUri(request.getServletPath().concat("===")
.concat(request.getMethod()).toLowerCase()).build();
assertFalse(pathRoleMatcher.isExcludedResource(subject));
verify(request);
......
......@@ -28,6 +28,14 @@ class SurenessSecurityManagerTest {
private static final String AUTHORIZATION = "Authorization";
private static final String BASIC = "Basic";
private static final String BEARER = "Bearer";
private static final String DEFAULT_SECRET_KEY =
"MIIEowIBAl+f/dKhaX0csgOCTlCxq20yhmUea6H6JIpST3ST1SE2Rwp" +
"LnfKefTjsIfJLBa2YkhEqE/GtcHDTNe4CU6+9y/S5z50Kik70LsP43r" +
"RnLN7XNn4wARoQXizIv6MHUsIV+EFfiMw/x7R0ntu4aWr/CWuApcFaj" +
"4mWEa6EwrPHTZmbT5Mt45AM2UYhzDHK+0F0rUq3MwH+oXsm+L3F/zjj" +
"M6EByXIO+SV5+8tVt4bisXQ13rbN0oxhUZR73+LDj9mxa6rFhMW+lfx" +
"CyaFv0bwq2Eik0jdrKUtsA6bx3sDJeFV643R+YYzGMRIqcBIp6AKA98" +
"GM2RIqcBIp6-?::4390fsf4sdl6opf)4ZI:tdQMtcQQ14pkOAQdQ546";
private static SecurityManager securityManager;
......@@ -38,6 +46,7 @@ class SurenessSecurityManagerTest {
assertDoesNotThrow(SurenessSecurityManager::getInstance);
securityManager = SurenessSecurityManager.getInstance();
assertNotNull(securityManager);
JsonWebTokenUtil.setDefaultSecretKey(DEFAULT_SECRET_KEY);
}
@Test
......@@ -47,7 +56,7 @@ class SurenessSecurityManagerTest {
expect(request.getHeader(AUTHORIZATION)).andStubReturn(BASIC + " "
+ new String(Base64.getEncoder().encode("admin:admin".getBytes(StandardCharsets.UTF_8))));
expect(request.getRequestURI()).andStubReturn("/api/v2/host");
expect(request.getServletPath()).andStubReturn("/api/v2/host");
expect(request.getMethod()).andStubReturn("put");
expect(request.getRemoteHost()).andStubReturn("192.167.2.1");
replay(request);
......@@ -63,7 +72,7 @@ class SurenessSecurityManagerTest {
expect(request.getHeader(AUTHORIZATION)).andStubReturn(BASIC + " "
+ new String(Base64.getEncoder().encode("admin:1234".getBytes(StandardCharsets.UTF_8))));
expect(request.getRequestURI()).andStubReturn("/api/v1/book");
expect(request.getServletPath()).andStubReturn("/api/v1/book");
expect(request.getMethod()).andStubReturn("put");
expect(request.getRemoteHost()).andStubReturn("192.167.2.1");
replay(request);
......@@ -77,7 +86,7 @@ class SurenessSecurityManagerTest {
null, Boolean.FALSE);
HttpServletRequest request = createNiceMock(HttpServletRequest.class);
expect(request.getHeader(AUTHORIZATION)).andStubReturn(BEARER + " " + jwt);
expect(request.getRequestURI()).andStubReturn("/api/v1/source1");
expect(request.getServletPath()).andStubReturn("/api/v1/source1");
expect(request.getMethod()).andStubReturn("get");
expect(request.getRemoteHost()).andStubReturn("192.167.2.1");
replay(request);
......
......@@ -48,7 +48,7 @@ class SurenessSubjectFactoryTest {
HttpServletRequest request = createNiceMock(HttpServletRequest.class);
expect(request.getHeader(AUTHORIZATION)).andStubReturn(BASIC + " "
+ new String(Base64.getEncoder().encode("admin:admin".getBytes(StandardCharsets.UTF_8))));
expect(request.getRequestURI()).andStubReturn("/api/v1/book");
expect(request.getServletPath()).andStubReturn("/api/v1/book");
expect(request.getMethod()).andStubReturn("put");
expect(request.getRemoteHost()).andStubReturn("192.167.2.1");
replay(request);
......
......@@ -49,7 +49,7 @@ public class BasicSubjectServletCreatorTest {
HttpServletRequest request = createNiceMock(HttpServletRequest.class);
expect(request.getHeader(AUTHORIZATION)).andReturn(BASIC + " "
+ new String(Base64.getEncoder().encode("admin:admin".getBytes(StandardCharsets.UTF_8))));
expect(request.getRequestURI()).andReturn("/api/v1/book");
expect(request.getServletPath()).andReturn("/api/v1/book");
expect(request.getMethod()).andReturn("put");
expect(request.getRemoteHost()).andReturn("192.167.2.1");
replay(request);
......
......@@ -43,7 +43,7 @@ class DigestSubjectServletCreatorTest {
expect(request.getHeader(AUTHORIZATION)).andReturn("Digest username=\"tom\", realm=\"sureness_realm\", " +
"nonce=\"c3403e810156a6131c4333eaa27f0797\", uri=\"/api/v1/source1\", response=\"86c3684d94ebc9786e6e7b6cbb288cfe\", qop=auth, nc=00000002, cnonce=\"4ee455aebd085f01\"");
expect(request.getRequestURI()).andReturn("/api/v1/book");
expect(request.getServletPath()).andReturn("/api/v1/book");
expect(request.getMethod()).andReturn("put");
expect(request.getRemoteHost()).andReturn("192.167.2.1");
replay(request);
......
......@@ -21,12 +21,21 @@ public class JwtSubjectServletCreatorTest {
private static final String AUTHORIZATION = "Authorization";
private static final String BEARER = "Bearer";
private static final String DEFAULT_SECRET_KEY =
"MIIEowIBAl+f/dKhaX0csgOCTlCxq20yhmUea6H6JIpST3ST1SE2Rwp" +
"LnfKefTjsIfJLBa2YkhEqE/GtcHDTNe4CU6+9y/S5z50Kik70LsP43r" +
"RnLN7XNn4wARoQXizIv6MHUsIV+EFfiMw/x7R0ntu4aWr/CWuApcFaj" +
"4mWEa6EwrPHTZmbT5Mt45AM2UYhzDHK+0F0rUq3MwH+oXsm+L3F/zjj" +
"M6EByXIO+SV5+8tVt4bisXQ13rbN0oxhUZR73+LDj9mxa6rFhMW+lfx" +
"CyaFv0bwq2Eik0jdrKUtsA6bx3sDJeFV643R+YYzGMRIqcBIp6AKA98" +
"GM2RIqcBIp6-?::4390fsf4sdl6opf)4ZI:tdQMtcQQ14pkOAQdQ546";
private SubjectCreate creator;
@BeforeEach
public void setUp() {
creator = new JwtSubjectServletCreator();
JsonWebTokenUtil.setDefaultSecretKey(DEFAULT_SECRET_KEY);
}
......@@ -49,7 +58,7 @@ public class JwtSubjectServletCreatorTest {
null, Boolean.FALSE);
HttpServletRequest request = createNiceMock(HttpServletRequest.class);
expect(request.getHeader(AUTHORIZATION)).andReturn(BEARER + " " + jwt);
expect(request.getRequestURI()).andReturn("/api/v1/book");
expect(request.getServletPath()).andReturn("/api/v1/book");
expect(request.getMethod()).andReturn("put");
expect(request.getRemoteHost()).andReturn("192.167.2.1");
replay(request);
......
......@@ -35,7 +35,7 @@ public class NoneSubjectServletCreatorTest {
@Test
public void createSubject() {
HttpServletRequest request = createNiceMock(HttpServletRequest.class);
expect(request.getRequestURI()).andReturn("/api/v1/book");
expect(request.getServletPath()).andReturn("/api/v1/book");
expect(request.getMethod()).andReturn("put");
expect(request.getRemoteHost()).andReturn("192.167.2.1");
replay(request);
......
package com.usthe.sureness.util;
import io.jsonwebtoken.Claims;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.*;
......@@ -14,6 +16,20 @@ import static org.junit.jupiter.api.Assertions.*;
*/
public class JsonWebTokenUtilTest {
private static final String DEFAULT_SECRET_KEY =
"MIIEowIBAl+f/dKhaX0csgOCTlCxq20yhmUea6H6JIpST3ST1SE2Rwp" +
"LnfKefTjsIfJLBa2YkhEqE/GtcHDTNe4CU6+9y/S5z50Kik70LsP43r" +
"RnLN7XNn4wARoQXizIv6MHUsIV+EFfiMw/x7R0ntu4aWr/CWuApcFaj" +
"4mWEa6EwrPHTZmbT5Mt45AM2UYhzDHK+0F0rUq3MwH+oXsm+L3F/zjj" +
"M6EByXIO+SV5+8tVt4bisXQ13rbN0oxhUZR73+LDj9mxa6rFhMW+lfx" +
"CyaFv0bwq2Eik0jdrKUtsA6bx3sDJeFV643R+YYzGMRIqcBIp6AKA98" +
"GM2RIqcBIp6-?::4390fsf4sdl6opf)4ZI:tdQMtcQQ14pkOAQdQ546";
@BeforeEach
public void before() {
JsonWebTokenUtil.setDefaultSecretKey(DEFAULT_SECRET_KEY);
}
@Test
public void issueJwt() {
String jwt = JsonWebTokenUtil.issueJwt(UUID.randomUUID().toString(), "tom",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册