Skip to content

Commit

Permalink
#300 Refactored utility class to have more protection against concurr…
Browse files Browse the repository at this point in the history
…ency problems
  • Loading branch information
svenkubiak committed Apr 21, 2017
1 parent 0f57968 commit 30f8061
Show file tree
Hide file tree
Showing 30 changed files with 215 additions and 338 deletions.
4 changes: 2 additions & 2 deletions mangooio-core/src/main/java/io/mangoo/core/Bootstrap.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,9 @@ private void createRoutes() {
this.pathHandler = new PathHandler(getRoutingHandler());
for (final Route route : Router.getRoutes()) {
if (RouteType.WEBSOCKET == route.getRouteType()) {
this.pathHandler.addExactPath(route.getUrl(), Handlers.websocket(new WebSocketHandler(route.getControllerClass(), route.isAuthenticationRequired())));
this.pathHandler.addExactPath(route.getUrl(), Handlers.websocket(this.injector.getInstance(WebSocketHandler.class).withControllerClass((route.getControllerClass())).withAuthentication(route.isAuthenticationRequired())));
} else if (RouteType.SERVER_SENT_EVENT == route.getRouteType()) {
this.pathHandler.addExactPath(route.getUrl(), Handlers.serverSentEvents(new ServerSentEventHandler(route.isAuthenticationRequired())));
this.pathHandler.addExactPath(route.getUrl(), Handlers.serverSentEvents(this.injector.getInstance(ServerSentEventHandler.class).withAuthentication(route.isAuthenticationRequired())));
} else if (RouteType.RESOURCE_PATH == route.getRouteType()) {
this.pathHandler.addPrefixPath(route.getUrl(), new ResourceHandler(new ClassPathResourceManager(Thread.currentThread().getContextClassLoader(), Default.FILES_FOLDER.toString() + route.getUrl())));
}
Expand Down
4 changes: 3 additions & 1 deletion mangooio-core/src/main/java/io/mangoo/enums/Required.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public enum Required {
PLAIN_TEXT("plan text can not be null"),
RECIPIENT("recipient can not be null"),
REDIRECT_TO("redirect to can not be null"),
REQUEST_HELPER("requesthelper can not be null"),
REQUEST_PARAMETER("request parameter can not be null"),
RESPONSE("response can not be null"),
ROUTE("route can not be null"),
Expand All @@ -87,7 +88,8 @@ public enum Required {
USERNAME("username can not be null"),
VALIDATOR("validator can not be null"),
VALUE("value can not be null"),
VALUES("values can not be null");
VALUES("values can not be null"),
TWO_FACTOR_HELPER("twofactorhelper can not be null");

private final String value;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.mangoo.filters.oauth;

import java.io.IOException;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException;

Expand All @@ -16,17 +17,19 @@
import com.github.scribejava.core.oauth.OAuth10aService;
import com.github.scribejava.core.oauth.OAuth20Service;
import com.github.scribejava.core.oauth.OAuthService;
import com.google.inject.Inject;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.ReadContext;

import io.mangoo.enums.Default;
import io.mangoo.enums.Required;
import io.mangoo.enums.oauth.OAuthProvider;
import io.mangoo.enums.oauth.OAuthResource;
import io.mangoo.helpers.RequestHelper;
import io.mangoo.interfaces.MangooFilter;
import io.mangoo.models.OAuthUser;
import io.mangoo.routing.Response;
import io.mangoo.routing.bindings.Request;
import io.mangoo.utils.RequestUtils;

/**
* Callback filter when returning from an OAuth authentication
Expand All @@ -45,10 +48,16 @@ public class OAuthCallbackFilter implements MangooFilter {
private static final String OAUTH_VERIFIER = "oauth_verifier";
private static final String OAUTH_TOKEN = "oauth_token";
private static final String CODE = "code";
private final RequestHelper requestHelper;

@Inject
public OAuthCallbackFilter(RequestHelper requestHelper) {
this.requestHelper = Objects.requireNonNull(requestHelper, Required.REQUEST_HELPER.toString());
}

@Override
public Response execute(Request request, Response response) {
final Optional<OAuthProvider> oAuthProvider = RequestUtils.getOAuthProvider(request.getParameter(Default.OAUTH_REQUEST_PARAMETER.toString()));
final Optional<OAuthProvider> oAuthProvider = this.requestHelper.getOAuthProvider(request.getParameter(Default.OAUTH_REQUEST_PARAMETER.toString()));
if (oAuthProvider.isPresent()) {
switch (oAuthProvider.get()) {
case TWITTER:
Expand Down Expand Up @@ -76,7 +85,7 @@ public Response execute(Request request, Response response) {
@SuppressWarnings("rawtypes")
private void facebookOAuth(Request request) {
final String code = request.getParameter(CODE);
final Optional<OAuthService> oAuthService = RequestUtils.createOAuthService(OAuthProvider.FACEBOOK);
final Optional<OAuthService> oAuthService = this.requestHelper.createOAuthService(OAuthProvider.FACEBOOK);

if (StringUtils.isNotBlank(code) && oAuthService.isPresent()) {
final OAuth20Service oAuth20Service = (OAuth20Service ) oAuthService.get();
Expand Down Expand Up @@ -113,7 +122,7 @@ private void facebookOAuth(Request request) {
@SuppressWarnings("rawtypes")
private void googleOAuth(Request request) {
final String code = request.getParameter(CODE);
final Optional<OAuthService> oAuthService = RequestUtils.createOAuthService(OAuthProvider.GOOGLE);
final Optional<OAuthService> oAuthService = this.requestHelper.createOAuthService(OAuthProvider.GOOGLE);

if (StringUtils.isNotBlank(code) && oAuthService.isPresent()) {
final OAuth20Service oAuth20Service = (OAuth20Service) oAuthService.get();
Expand Down Expand Up @@ -151,7 +160,7 @@ private void googleOAuth(Request request) {
private void twitterOAuth(Request request) {
final String oauthToken = request.getParameter(OAUTH_TOKEN);
final String oauthVerifier = request.getParameter(OAUTH_VERIFIER);
final Optional<OAuthService> oAuthService = RequestUtils.createOAuthService(OAuthProvider.TWITTER);
final Optional<OAuthService> oAuthService = this.requestHelper.createOAuthService(OAuthProvider.TWITTER);

if (StringUtils.isNotBlank(oauthToken) && StringUtils.isNotBlank(oauthVerifier) && oAuthService.isPresent()) {
final OAuth1RequestToken requestToken = new OAuth1RequestToken(oauthToken, oauthVerifier);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.net.URI;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException;

Expand All @@ -13,13 +14,15 @@
import com.github.scribejava.core.oauth.OAuth10aService;
import com.github.scribejava.core.oauth.OAuth20Service;
import com.github.scribejava.core.oauth.OAuthService;
import com.google.inject.Inject;

import io.mangoo.enums.Default;
import io.mangoo.enums.Required;
import io.mangoo.enums.oauth.OAuthProvider;
import io.mangoo.helpers.RequestHelper;
import io.mangoo.interfaces.MangooFilter;
import io.mangoo.routing.Response;
import io.mangoo.routing.bindings.Request;
import io.mangoo.utils.RequestUtils;

/**
* OAuth Login filter for redirecting to the OAuth provider
Expand All @@ -28,14 +31,20 @@
*
*/
public class OAuthLoginFilter implements MangooFilter {
private static final Logger LOG = LogManager.getLogger(OAuthCallbackFilter.class);
private static final Logger LOG = LogManager.getLogger(OAuthLoginFilter.class);
private final RequestHelper requestHelper;

@Inject
public OAuthLoginFilter(RequestHelper requestHelper) {
this.requestHelper = Objects.requireNonNull(requestHelper, Required.REQUEST_HELPER.toString());
}

@Override
@SuppressWarnings("rawtypes")
public Response execute(Request request, Response response) {
Optional<OAuthProvider> oAuthProvider = RequestUtils.getOAuthProvider(request.getParameter(Default.OAUTH_REQUEST_PARAMETER.toString()));
Optional<OAuthProvider> oAuthProvider = this.requestHelper.getOAuthProvider(request.getParameter(Default.OAUTH_REQUEST_PARAMETER.toString()));
if (oAuthProvider.isPresent()) {
Optional<OAuthService> oAuthService = RequestUtils.createOAuthService(oAuthProvider.get());
Optional<OAuthService> oAuthService = this.requestHelper.createOAuthService(oAuthProvider.get());
if (oAuthService.isPresent()) {
String url = null;
switch (oAuthProvider.get()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.mangoo.utils;
package io.mangoo.helpers;

import java.net.URI;
import java.security.SecureRandom;
Expand Down Expand Up @@ -54,7 +54,7 @@
* @author svenkubiak
*
*/
public final class RequestUtils {
public class RequestHelper {
public static final AttachmentKey<Attachment> ATTACHMENT_KEY = AttachmentKey.create(Attachment.class);
private static final String SCOPE = "https://www.googleapis.com/auth/userinfo.email";
private static final int MAX_RANDOM = 999_999;
Expand All @@ -63,16 +63,13 @@ public final class RequestUtils {
private static final int INDEX_1 = 1;
private static final int INDEX_2 = 2;

private RequestUtils() {
}

/**
* Converts request and query parameter into a single map
*
* @param exchange The Undertow HttpServerExchange
* @return A single map contain both request and query parameter
*/
public static Map<String, String> getRequestParameters(HttpServerExchange exchange) {
public Map<String, String> getRequestParameters(HttpServerExchange exchange) {
Objects.requireNonNull(exchange, Required.HTTP_SERVER_EXCHANGE.toString());

final Map<String, String> requestParamater = new HashMap<>();
Expand All @@ -92,7 +89,7 @@ public static Map<String, String> getRequestParameters(HttpServerExchange exchan
* @return True if the request is a POST or a PUT request, false otherwise
*/
@Deprecated
public static boolean isPostOrPut(HttpServerExchange exchange) {
public boolean isPostOrPut(HttpServerExchange exchange) {
Objects.requireNonNull(exchange, Required.HTTP_SERVER_EXCHANGE.toString());

return (Methods.POST).equals(exchange.getRequestMethod()) || (Methods.PUT).equals(exchange.getRequestMethod());
Expand All @@ -104,7 +101,7 @@ public static boolean isPostOrPut(HttpServerExchange exchange) {
* @param exchange The Undertow HttpServerExchange
* @return True if the request is a POST, PUT or PATCH request, false otherwise
*/
public static boolean isPostPutPatch(HttpServerExchange exchange) {
public boolean isPostPutPatch(HttpServerExchange exchange) {
Objects.requireNonNull(exchange, Required.HTTP_SERVER_EXCHANGE.toString());

return (Methods.POST).equals(exchange.getRequestMethod()) || (Methods.PUT).equals(exchange.getRequestMethod()) || (Methods.PATCH).equals(exchange.getRequestMethod());
Expand All @@ -116,7 +113,7 @@ public static boolean isPostPutPatch(HttpServerExchange exchange) {
* @param exchange The Undertow HttpServerExchange
* @return True if the request content-type contains application/json, false otherwise
*/
public static boolean isJsonRequest(HttpServerExchange exchange) {
public boolean isJsonRequest(HttpServerExchange exchange) {
Objects.requireNonNull(exchange, Required.HTTP_SERVER_EXCHANGE.toString());

final HeaderMap headerMap = exchange.getRequestHeaders();
Expand All @@ -131,7 +128,7 @@ public static boolean isJsonRequest(HttpServerExchange exchange) {
* @return An OAuthService object or null if creating failed
*/
@SuppressWarnings("rawtypes")
public static Optional<OAuthService> createOAuthService(OAuthProvider oAuthProvider) {
public Optional<OAuthService> createOAuthService(OAuthProvider oAuthProvider) {
Objects.requireNonNull(oAuthProvider, Required.OAUTH_PROVIDER.toString());

Config config = Application.getInstance(Config.class);
Expand Down Expand Up @@ -174,7 +171,7 @@ public static Optional<OAuthService> createOAuthService(OAuthProvider oAuthProvi
* @param oauth The string to lookup the OAuthProvider Enum
* @return OAuthProvider Enum
*/
public static Optional<OAuthProvider> getOAuthProvider(String oauth) {
public Optional<OAuthProvider> getOAuthProvider(String oauth) {
OAuthProvider oAuthProvider = null;
if (OAuthProvider.FACEBOOK.toString().equals(oauth)) {
oAuthProvider = OAuthProvider.FACEBOOK;
Expand All @@ -193,7 +190,7 @@ public static Optional<OAuthProvider> getOAuthProvider(String oauth) {
* @param cookieHeader The header to parse
* @return True if the cookie contains a valid authentication, false otherwise
*/
public static boolean hasValidAuthentication(String cookieHeader) {
public boolean hasValidAuthentication(String cookieHeader) {
boolean validAuthentication = false;
if (StringUtils.isNotBlank(cookieHeader)) {
final Map<String, Cookie> cookies = Cookies.parseRequestCookies(1, false, Arrays.asList(cookieHeader));
Expand Down Expand Up @@ -240,7 +237,7 @@ public static boolean hasValidAuthentication(String cookieHeader) {
*
* @return The URL of the Server-Sent Event Connection
*/
public static String getServerSentEventURL(ServerSentEventConnection connection) {
public String getServerSentEventURL(ServerSentEventConnection connection) {
return getURL(URI.create(connection.getRequestURI()));
}

Expand All @@ -251,7 +248,7 @@ public static String getServerSentEventURL(ServerSentEventConnection connection)
*
* @return The URL of the WebSocket Channel
*/
public static String getWebSocketURL(WebSocketChannel channel) {
public String getWebSocketURL(WebSocketChannel channel) {
return getURL(URI.create(channel.getUrl()));
}

Expand All @@ -262,7 +259,7 @@ public static String getWebSocketURL(WebSocketChannel channel) {
* @param uri The URI to generate from
* @return The generated URL
*/
private static String getURL(URI uri) {
private String getURL(URI uri) {
final StringBuilder buffer = new StringBuilder();
buffer.append(uri.getPath());

Expand All @@ -288,7 +285,7 @@ private static String getURL(URI uri) {
* @param password The password to use
* @return An HttpHandler wrapped through BasicAuthentication
*/
public static HttpHandler wrapSecurity(HttpHandler httpHandler, String username, String password) {
public HttpHandler wrapSecurity(HttpHandler httpHandler, String username, String password) {
Objects.requireNonNull(httpHandler, Required.HTTP_HANDLER.toString());
Objects.requireNonNull(username, Required.USERNAME.toString());
Objects.requireNonNull(password, Required.PASSWORD.toString());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.mangoo.utils;
package io.mangoo.helpers;

import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
Expand Down Expand Up @@ -32,16 +32,13 @@
* @author graywatson, svenkubiak, WilliamDunne
*/
@SuppressWarnings("all")
public final class TwoFactorUtils {
private static final Logger LOG = LogManager.getLogger(TwoFactorUtils.class);
private static final Base32 base32 = new Base32();
private static final String HMAC_SHA1 = "HmacSHA1";
private static final String BLOCK_OF_ZEROS = "000000";
private static final int TIME_STEP_SECONDS = 30;
private static final boolean USE_SHA1_THREAD_LOCAL = true;

private TwoFactorUtils() {
}
public class TwoFactorHelper {
private final Logger LOG = LogManager.getLogger(TwoFactorHelper.class);
private final Base32 base32 = new Base32();
private final String HMAC_SHA1 = "HmacSHA1";
private final String BLOCK_OF_ZEROS = "000000";
private final int TIME_STEP_SECONDS = 30;
private final boolean USE_SHA1_THREAD_LOCAL = true;

/**
* Validate a given code using the secret, defaults to window of 3 either side,
Expand All @@ -55,7 +52,7 @@ private TwoFactorUtils() {
*
* @return boolean if the code is valid
*/
public static boolean validateCurrentNumber(int number, String secret) {
public boolean validateCurrentNumber(int number, String secret) {
return validateCurrentNumber(number, secret, 3);
}

Expand All @@ -69,7 +66,7 @@ public static boolean validateCurrentNumber(int number, String secret) {
*
* @return True if the code is valid within the timeframe, false otherwise
*/
public static boolean validateCurrentNumber(int number, String secret, int window, long time) {
public boolean validateCurrentNumber(int number, String secret, int window, long time) {
try {
int current = Integer.parseInt(generateCurrentNumber(secret, time));
if (number == current) {
Expand Down Expand Up @@ -97,13 +94,13 @@ public static boolean validateCurrentNumber(int number, String secret, int windo
*
* @return True if the code is correct, false otherwise
*/
public static boolean validateCurrentNumber(int number, String secret, int window) {
public boolean validateCurrentNumber(int number, String secret, int window) {
long time = System.currentTimeMillis();

return validateCurrentNumber(number, secret, window, time);
}

private static boolean validateCurrentNumberLow(int number, String secret, int window, Long time) throws GeneralSecurityException {
private boolean validateCurrentNumberLow(int number, String secret, int window, Long time) throws GeneralSecurityException {
int current = Integer.parseInt(generateCurrentNumber(secret, time));
if (current == number) {
return true;
Expand All @@ -116,7 +113,7 @@ private static boolean validateCurrentNumberLow(int number, String secret, int w
return false;
}

private static boolean validateCurrentNumberHigh(int number, String secret, int window, long time) throws GeneralSecurityException {
private boolean validateCurrentNumberHigh(int number, String secret, int window, long time) throws GeneralSecurityException {
int current = Integer.parseInt(generateCurrentNumber(secret, time));
if (current == number) {
return true;
Expand All @@ -142,7 +139,7 @@ private static boolean validateCurrentNumberHigh(int number, String secret, int
*
* @return The current number to be checked
*/
public static String generateCurrentNumber(String secret) {
public String generateCurrentNumber(String secret) {
Objects.requireNonNull(secret, Required.SECRET.toString());

return generateCurrentNumber(secret, System.currentTimeMillis());
Expand All @@ -156,7 +153,7 @@ public static String generateCurrentNumber(String secret) {
*
* @return The current number to be checked
*/
public static String generateCurrentNumber(String secret, long currentTimeMillis) {
public String generateCurrentNumber(String secret, long currentTimeMillis) {
Objects.requireNonNull(secret, Required.GROUP_NAME.toString());

final byte[] key = secret.getBytes();
Expand Down Expand Up @@ -203,7 +200,7 @@ public static String generateCurrentNumber(String secret, long currentTimeMillis
*
* @return A URL to the Google charts API
*/
public static String generateQRCode(String accountName, String secret) {
public String generateQRCode(String accountName, String secret) {
Objects.requireNonNull(accountName, Required.ACCOUNT_NAME.toString());
Objects.requireNonNull(secret, Required.SECRET.toString());

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.mangoo.utils.cookie;
package io.mangoo.helpers.cookie;

import java.time.LocalDateTime;
import java.time.ZoneId;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.mangoo.utils.cookie;
package io.mangoo.helpers.cookie;

import java.time.Instant;
import java.time.LocalDateTime;
Expand Down
Loading

0 comments on commit 30f8061

Please sign in to comment.