Skip to content

Commit

Permalink
Refactored token and security management (serializing only when chang…
Browse files Browse the repository at this point in the history
…ed).
  • Loading branch information
nmihajlovski committed Aug 18, 2016
1 parent 94fbc1c commit 1e47772
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 14 deletions.
1 change: 1 addition & 0 deletions rapidoid-commons/src/main/resources/rapidoid-classes.txt
Expand Up @@ -371,6 +371,7 @@ org.rapidoid.http.impl.RespImpl
org.rapidoid.http.impl.ResponseRenderer
org.rapidoid.http.impl.RouteImpl
org.rapidoid.http.impl.RouteOptions
org.rapidoid.http.impl.TokenStatus
org.rapidoid.http.NotFound
org.rapidoid.http.processor.AbstractHttpProcessor
org.rapidoid.http.processor.HttpProcessor
Expand Down
Expand Up @@ -5,6 +5,7 @@
import org.rapidoid.annotation.Since;
import org.rapidoid.buffer.Buf;
import org.rapidoid.cls.Cls;
import org.rapidoid.commons.Coll;
import org.rapidoid.commons.MediaType;
import org.rapidoid.commons.Str;
import org.rapidoid.http.*;
Expand All @@ -23,6 +24,7 @@
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;

/*
* #%L
Expand Down Expand Up @@ -86,6 +88,10 @@ public class ReqImpl extends RapidoidThing implements Req, Constants, HttpMetada

private volatile Map<String, Serializable> token;

final AtomicBoolean isTokenDirty = new AtomicBoolean();

private volatile TokenStatus tokenStatus = TokenStatus.PENDING;

private volatile Map<String, Serializable> session;

private volatile RespImpl response;
Expand Down Expand Up @@ -419,7 +425,7 @@ public void startRendering(int code, boolean unknownContentLength) {
private void startResponse(int code, boolean unknownContentLength) {
MediaType contentType = MediaType.HTML_UTF_8;

if (token != null) {
if (isTokenDirty.get()) {
HttpUtils.saveTokenBeforeRenderingHeaders(this, token);
}

Expand Down Expand Up @@ -674,24 +680,29 @@ public <T extends Serializable> T session(String name, T defaultValue) {

@Override
public boolean hasToken() {
return U.notEmpty(token) || cookie(TOKEN, null) != null || data(TOKEN, null) != null;
token(); // try to find and deserialize the token
return tokenStatus != TokenStatus.NONE;
}

@Override
public Map<String, Serializable> token() {
if (token == null) {
if (tokenStatus == TokenStatus.PENDING) {
synchronized (this) {
if (token == null) {
Map<String, Serializable> cpack = null;
if (tokenStatus == TokenStatus.PENDING) {

Map<String, Serializable> tokenData = null;

try {
cpack = HttpUtils.initAndDeserializeToken(this);
tokenData = HttpUtils.initAndDeserializeToken(this);

tokenStatus(tokenData != null ? TokenStatus.LOADED : TokenStatus.NONE);

} catch (Exception e) {
Log.warn("Cookie-pack deserialization error! Maybe the secret was changed?");
Log.debug("Cookie-pack deserialization error!", e);
Log.debug("Token deserialization error!", e);
tokenStatus(TokenStatus.INVALID);
}

token = Collections.synchronizedMap(U.safe(cpack));
token = Coll.trackChanges(Collections.synchronizedMap(U.safe(tokenData)), isTokenDirty);
}
}
}
Expand All @@ -712,6 +723,15 @@ public <T extends Serializable> T token(String name, T defaultValue) {
return withDefault(value, defaultValue);
}

public TokenStatus tokenStatus() {
return tokenStatus;
}

public Req tokenStatus(TokenStatus tokenStatus) {
this.tokenStatus = tokenStatus;
return this;
}

@Override
public String segment() {
return segment;
Expand Down
Expand Up @@ -322,12 +322,15 @@ public Req request() {

@Override
public boolean login(String username, String password) {

LoginProvider loginProvider = Customization.of(req).loginProvider();
U.must(loginProvider != null, "A login provider wasn't set!");

RolesProvider rolesProvider = Customization.of(req).rolesProvider();
U.must(rolesProvider != null, "A roles provider wasn't set!");

req.isTokenDirty.set(true);

boolean success;

try {
Expand Down Expand Up @@ -356,6 +359,7 @@ public boolean login(String username, String password) {
public void logout() {
HttpUtils.clearUserData(request());
HttpUtils.setResponseTokenCookie(this, "");
req.isTokenDirty.set(true);
}

@Override
Expand Down
@@ -0,0 +1,32 @@
package org.rapidoid.http.impl;

/*
* #%L
* rapidoid-http-fast
* %%
* Copyright (C) 2014 - 2016 Nikolche Mihajlovski and contributors
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/

import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;

@Authors("Nikolche Mihajlovski")
@Since("5.2.0")
public enum TokenStatus {

PENDING, NONE, LOADED, INVALID;

}
Expand Up @@ -3,7 +3,6 @@ Connection: keep-alive
Server: Rapidoid
Date: XXXXX GMT
Content-Type: application/json; charset=utf-8
Set-Cookie: _token=...; path=/; HttpOnly
Content-Length: 5

"abc"
Expand Up @@ -3,7 +3,6 @@ Connection: keep-alive
Server: Rapidoid
Date: XXXXX GMT
Content-Type: application/json; charset=utf-8
Set-Cookie: _token=...; path=/; HttpOnly
Content-Length: 7

"chuck"
Expand Up @@ -3,7 +3,6 @@ Connection: keep-alive
Server: Rapidoid
Date: XXXXX GMT
Content-Type: application/json; charset=utf-8
Set-Cookie: _token=...; path=/; HttpOnly
Content-Length: 5

"foo"
Expand Up @@ -3,7 +3,6 @@ Connection: keep-alive
Server: Rapidoid
Date: XXXXX GMT
Content-Type: application/json; charset=utf-8
Set-Cookie: _token=...; path=/; HttpOnly
Content-Length: 6

"niko"
Expand Up @@ -3,7 +3,6 @@ Connection: keep-alive
Server: Rapidoid
Date: XXXXX GMT
Content-Type: application/json; charset=utf-8
Set-Cookie: _token=; path=/; HttpOnly
Content-Length: 85

{"error":"The user doesn't have the required roles!","code":403,"status":"Forbidden"}

0 comments on commit 1e47772

Please sign in to comment.