Skip to content

Commit 72b194e

Browse files
committed
Added cookie validation
1 parent 2e4fe17 commit 72b194e

11 files changed

+218
-29
lines changed

QueueIT.Security/build.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,6 @@
7272
7373
-->
7474
<target name="-post-jar">
75-
<copy file="${dist.jar}" todir="../QueueIT.Security.Examples.Java/web/WEB-INF/lib"/>
75+
<copy file="${dist.jar}" todir="../QueueIT.Security.Examples/web/WEB-INF/lib"/>
7676
</target>
7777
</project>
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package queueit.security;
2+
3+
import java.io.InputStream;
4+
import java.io.UnsupportedEncodingException;
5+
import java.net.URI;
6+
import java.security.MessageDigest;
7+
import java.security.NoSuchAlgorithmException;
8+
import java.util.Date;
9+
import java.util.Properties;
10+
import java.util.UUID;
11+
import java.util.concurrent.Callable;
12+
import javax.servlet.http.*;
13+
import javax.xml.bind.DatatypeConverter;
14+
15+
public class CookieValidateResultRepository extends ValidateResultRepositoryBase {
16+
17+
static String defaultCookieDomain;
18+
19+
static {
20+
loadConfiguration();
21+
}
22+
23+
private static void loadConfiguration()
24+
{
25+
try {
26+
// Load the properties
27+
Properties props = new Properties();
28+
ClassLoader classLoader = CookieValidateResultRepository.class.getClassLoader();
29+
InputStream configFile = classLoader.getResourceAsStream("queueit.properties");
30+
if (configFile != null) {
31+
props.load(configFile);
32+
defaultCookieDomain = props.getProperty("cookieDomain", null);
33+
}
34+
} catch (Exception e) {
35+
// no need to handle exception
36+
}
37+
}
38+
@Override
39+
public IValidateResult getValidationResult(IQueue queue) {
40+
41+
String key = generateKey(queue.getCustomerId(), queue.getEventId());
42+
HttpServletRequest request = RequestContext.getCurrentInstance().getRequest();
43+
44+
String queueId = null;
45+
String originalUrl = null;
46+
String encryptedPlaceInQueue = null;
47+
String redirectType = null;
48+
String timeStamp = null;
49+
String actualHash = null;
50+
Integer placeInQueue = 0;
51+
52+
Cookie[] cookies = request.getCookies();
53+
for (int i = 0; i < cookies.length; i++)
54+
{
55+
if (cookies[i].getName().equals(key + "-QueueId"))
56+
queueId = cookies[i].getValue();
57+
if (cookies[i].getName().equals(key + "-OriginalUrl"))
58+
originalUrl = cookies[i].getValue();
59+
if (cookies[i].getName().equals(key + "-PlaceInQueue"))
60+
encryptedPlaceInQueue = cookies[i].getValue();
61+
if (cookies[i].getName().equals(key + "-RedirectType"))
62+
redirectType = cookies[i].getValue();
63+
if (cookies[i].getName().equals(key + "-TimeStamp"))
64+
timeStamp = cookies[i].getValue();
65+
if (cookies[i].getName().equals(key + "-Hash"))
66+
actualHash = cookies[i].getValue();
67+
}
68+
69+
if (queueId == null || originalUrl == null || encryptedPlaceInQueue == null || redirectType == null || timeStamp == null)
70+
return null;
71+
72+
try
73+
{
74+
placeInQueue = Hashing.decryptPlaceInQueue(encryptedPlaceInQueue);
75+
} catch (InvalidKnownUserUrlException ex) {
76+
return null;
77+
}
78+
79+
String expectedHash = generateHash(queueId, originalUrl, placeInQueue.toString(), redirectType, timeStamp);
80+
81+
if (!expectedHash.equals(actualHash))
82+
return null;
83+
84+
return new AcceptedConfirmedResult(
85+
queue,
86+
new Md5KnownUser(
87+
UUID.fromString(queueId),
88+
placeInQueue,
89+
new Date(Integer.parseInt(timeStamp)),
90+
queue.getCustomerId(),
91+
queue.getEventId(),
92+
RedirectType.valueOf(redirectType),
93+
URI.create(originalUrl)),
94+
false);
95+
}
96+
97+
@Override
98+
public void setValidationResult(IQueue queue, IValidateResult validationResult) {
99+
100+
if (validationResult instanceof AcceptedConfirmedResult)
101+
{
102+
AcceptedConfirmedResult confirmedResult = (AcceptedConfirmedResult)validationResult;
103+
104+
String key = generateKey(queue.getCustomerId(), queue.getEventId());
105+
HttpServletResponse response = RequestContext.getCurrentInstance().getResponse();
106+
107+
String queueId = confirmedResult.getKnownUser().getQueueId().toString();
108+
String originalUrl = confirmedResult.getKnownUser().getOriginalUrl().toString();
109+
Integer placeInQueue = confirmedResult.getKnownUser().getPlaceInQueue();
110+
String redirectType = confirmedResult.getKnownUser().getRedirectType().toString();
111+
Long timeStamp = confirmedResult.getKnownUser().getTimeStamp().getTime() / 1000;
112+
113+
String hash = generateHash(queueId, originalUrl, placeInQueue.toString(), redirectType, timeStamp.toString());
114+
115+
addCookie(new Cookie(key + "-QueueId", queueId), response);
116+
addCookie(new Cookie(key + "-OriginalUrl", originalUrl), response);
117+
addCookie(new Cookie(key + "-PlaceInQueue", Hashing.encryptPlaceInQueue(placeInQueue)), response);
118+
addCookie(new Cookie(key + "-RedirectType", redirectType), response);
119+
addCookie(new Cookie(key + "-TimeStamp", timeStamp.toString()), response);
120+
addCookie(new Cookie(key + "-Hash", hash), response);
121+
}
122+
}
123+
124+
private void addCookie(Cookie cookie, HttpServletResponse response)
125+
{
126+
cookie.setHttpOnly(true);
127+
if (defaultCookieDomain != null)
128+
cookie.setDomain(defaultCookieDomain);
129+
130+
response.addCookie(cookie);
131+
}
132+
133+
private String generateHash(String queueId, String originalUrl, String placeInQueue, String redirectType, String timeStamp) {
134+
try {
135+
StringBuilder sb = new StringBuilder();
136+
sb.append(queueId).append(originalUrl).append(placeInQueue).append(redirectType).append(timeStamp).append(KnownUserFactory.getSecretKey());
137+
138+
MessageDigest digest = MessageDigest.getInstance("SHA-256");
139+
byte[] hash = digest.digest(sb.toString().getBytes("UTF-8"));
140+
141+
return DatatypeConverter.printHexBinary(hash).toLowerCase();
142+
143+
} catch (NoSuchAlgorithmException ex) {
144+
// No such exception
145+
return null;
146+
} catch (UnsupportedEncodingException ex) {
147+
// No such exception
148+
return null;
149+
}
150+
}
151+
}

QueueIT.Security/src/queueit/security/Hashing.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.math.BigInteger;
44
import java.security.MessageDigest;
5+
import java.util.UUID;
56

67
public class Hashing {
78

@@ -18,6 +19,22 @@ public static Integer decryptPlaceInQueue(String encryptedPlaceInQueue) {
1819
String p = e.substring(30, 31) + e.substring(3, 4) + e.substring(11, 12) + e.substring(20, 21) + e.substring(7, 8) + e.substring(26, 27) + e.substring(9, 10);
1920
return Integer.parseInt(p);
2021
}
22+
23+
public static String encryptPlaceInQueue(Integer placeInQueue) {
24+
25+
char[] placeInQueueChars = String.format("%07d", placeInQueue).toCharArray();
26+
27+
char[] encryptedPlaceInQueue = UUID.randomUUID().toString().toCharArray();
28+
encryptedPlaceInQueue[9] = placeInQueueChars[6];
29+
encryptedPlaceInQueue[26] = placeInQueueChars[5];
30+
encryptedPlaceInQueue[7] = placeInQueueChars[4];
31+
encryptedPlaceInQueue[20] = placeInQueueChars[3];
32+
encryptedPlaceInQueue[11] = placeInQueueChars[2];
33+
encryptedPlaceInQueue[3] = placeInQueueChars[1];
34+
encryptedPlaceInQueue[30] = placeInQueueChars[0];
35+
36+
return new String(encryptedPlaceInQueue);
37+
}
2138

2239
static String getMd5Hash(String stringToHash) {
2340
try {
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package queueit.security;
22

33
public interface IValidateResultRepository {
4-
IValidateResult GetValidationResult(IQueue queue);
5-
void SetValidationResult(IQueue queue, IValidateResult validationResult);
4+
IValidateResult getValidationResult(IQueue queue);
5+
void setValidationResult(IQueue queue, IValidateResult validationResult);
66
}

QueueIT.Security/src/queueit/security/KnownUserFactory.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ public class KnownUserFactory {
1414
private static String defaultSecretKey;
1515
private static String defaultQuerystringPrefix;
1616
private static Callable<IKnownUserUrlProvider> defaultUrlProviderFactory;
17+
public static String getSecretKey() {
18+
return defaultSecretKey;
19+
}
1720

1821
static {
1922
defaultUrlProviderFactory = new Callable<IKnownUserUrlProvider>() {

QueueIT.Security/src/queueit/security/RequestContext.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
package queueit.security;
22

33
import javax.servlet.http.HttpServletRequest;
4+
import javax.servlet.http.HttpServletResponse;
45

56
public class RequestContext {
67
private static ThreadLocal<RequestContext> instance = new ThreadLocal<RequestContext>();
78
private HttpServletRequest request;
9+
private HttpServletResponse response;
810

9-
private RequestContext(HttpServletRequest request) {
11+
private RequestContext(HttpServletRequest request, HttpServletResponse response) {
1012
this.request = request;
13+
this.response = response;
1114
}
1215

1316
public static RequestContext getCurrentInstance() {
1417
return instance.get();
1518
}
1619

17-
public static RequestContext newInstance(HttpServletRequest request) {
18-
RequestContext context = new RequestContext(request);
20+
public static RequestContext newInstance(HttpServletRequest request, HttpServletResponse response) {
21+
RequestContext context = new RequestContext(request, response);
1922
instance.set(context);
2023
return context;
2124
}
@@ -27,4 +30,8 @@ public void release() {
2730
public HttpServletRequest getRequest() {
2831
return request;
2932
}
33+
34+
public HttpServletResponse getResponse() {
35+
return response;
36+
}
3037
}

QueueIT.Security/src/queueit/security/RequestContextFilter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import javax.servlet.ServletRequest;
99
import javax.servlet.ServletResponse;
1010
import javax.servlet.http.HttpServletRequest;
11+
import javax.servlet.http.HttpServletResponse;
1112

1213
public class RequestContextFilter implements Filter {
1314

@@ -18,7 +19,7 @@ public void init(FilterConfig fc) throws ServletException {
1819

1920
@Override
2021
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
21-
RequestContext context = RequestContext.newInstance((HttpServletRequest) request);
22+
RequestContext context = RequestContext.newInstance((HttpServletRequest) request, (HttpServletResponse)response);
2223
try {
2324
chain.doFilter(request, response);
2425
} finally {

QueueIT.Security/src/queueit/security/SessionValidateResultRepository.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
import javax.servlet.http.HttpServletRequest;
44
import javax.servlet.http.HttpSession;
55

6-
public class SessionValidateResultRepository implements IValidateResultRepository {
7-
private static String SessionQueueId = "QueueITAccepted-SDFrts345E-";
6+
public class SessionValidateResultRepository extends ValidateResultRepositoryBase {
7+
88

99
@Override
10-
public IValidateResult GetValidationResult(IQueue queue) {
10+
public IValidateResult getValidationResult(IQueue queue) {
1111
HttpServletRequest request = RequestContext.getCurrentInstance().getRequest();
1212
HttpSession session = request.getSession(true);
1313

@@ -16,16 +16,11 @@ public IValidateResult GetValidationResult(IQueue queue) {
1616
}
1717

1818
@Override
19-
public void SetValidationResult(IQueue queue, IValidateResult validationResult) {
19+
public void setValidationResult(IQueue queue, IValidateResult validationResult) {
2020
HttpServletRequest request = RequestContext.getCurrentInstance().getRequest();
2121
HttpSession session = request.getSession(true);
2222

2323
String key = generateKey(queue.getCustomerId(), queue.getEventId());
2424
session.setAttribute(key, validationResult);
25-
}
26-
27-
private static String generateKey(String customerId, String eventId)
28-
{
29-
return SessionQueueId + customerId + "-" + eventId;
30-
}
25+
}
3126
}

QueueIT.Security/src/queueit/security/SessionValidationController.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
public class SessionValidationController {
1111

1212
private static int defaultTicketExpiration = 0;
13-
private static IValidateResultRepository defaultValidationResultRepository = new SessionValidateResultRepository();
13+
private static IValidateResultRepository defaultValidationResultRepository = new CookieValidateResultRepository();
1414
private static Callable<IValidateResultRepository> defaultValidationResultProviderFactory = new Callable<IValidateResultRepository>() {
1515
public IValidateResultRepository call() {
1616
return defaultValidationResultRepository;
@@ -319,7 +319,7 @@ private static IValidateResult validateRequest(
319319
String layoutName) {
320320
IValidateResult sessionObject = null;
321321
try {
322-
sessionObject = defaultValidationResultProviderFactory.call().GetValidationResult(queue);
322+
sessionObject = defaultValidationResultProviderFactory.call().getValidationResult(queue);
323323
} catch (Exception ex) {
324324
// ignore
325325
}
@@ -357,7 +357,7 @@ private static IValidateResult validateRequest(
357357

358358
AcceptedConfirmedResult result = new AcceptedConfirmedResult(queue, knownUser, true);
359359
try {
360-
defaultValidationResultProviderFactory.call().SetValidationResult(queue, result);
360+
defaultValidationResultProviderFactory.call().setValidationResult(queue, result);
361361
} catch (Exception ex) {
362362
//ignore
363363
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package queueit.security;
2+
3+
public abstract class ValidateResultRepositoryBase implements IValidateResultRepository{
4+
private static String SessionQueueId = "QueueITAccepted-SDFrts345E-";
5+
6+
@Override
7+
public abstract IValidateResult getValidationResult(IQueue queue);
8+
@Override
9+
public abstract void setValidationResult(IQueue queue, IValidateResult validationResult);
10+
11+
protected static String generateKey(String customerId, String eventId)
12+
{
13+
return SessionQueueId + customerId + "-" + eventId;
14+
}
15+
}

0 commit comments

Comments
 (0)