Improved AuthenticationException.
Change-Id: I5c621a1da2df73b3dfb864771d2e9c03bf64942f
diff --git a/core/src/main/java/de/ids_mannheim/korap/config/Attributes.java b/core/src/main/java/de/ids_mannheim/korap/config/Attributes.java
index a43e2f3..03cea54 100644
--- a/core/src/main/java/de/ids_mannheim/korap/config/Attributes.java
+++ b/core/src/main/java/de/ids_mannheim/korap/config/Attributes.java
@@ -4,11 +4,11 @@
// EM: Use enum for the authentication types
public static final String AUTHORIZATION = "Authorization";
- public static final String SESSION_AUTHENTICATION = "session_token";
- public static final String API_AUTHENTICATION = "api_token";
- public static final String OAUTH2_AUTHORIZATION = "bearer";
- public static final String OPENID_AUTHENTICATION = "id_token";
- public static final String BASIC_AUTHENTICATION = "basic";
+// public static final String SESSION_AUTHENTICATION = "session_token";
+// public static final String API_AUTHENTICATION = "api_token";
+// public static final String OAUTH2_AUTHORIZATION = "bearer";
+// public static final String OPENID_AUTHENTICATION = "id_token";
+// public static final String BASIC_AUTHENTICATION = "basic";
public static final String LOCATION = "location"; // location of Client: User.INTERN/EXTERN
public static final String CORPUS_ACCESS = "corpusAccess"; // User.ALL/PUB/FREE.
@@ -62,7 +62,7 @@
* token context
*/
public static final String TOKEN = "token";
- public static final String AUTHENTICATION_TYPE = "authenticationType";
+ public static final String TOKEN_TYPE = "token_type";
public static final String TOKEN_EXPIRATION = "expires";
public static final String TOKEN_CREATION = "tokenCreated";
public static final String USER_AGENT = "User-Agent";
diff --git a/core/src/main/java/de/ids_mannheim/korap/user/TokenContext.java b/core/src/main/java/de/ids_mannheim/korap/user/TokenContext.java
index 16c2b2f..53dd34e 100644
--- a/core/src/main/java/de/ids_mannheim/korap/user/TokenContext.java
+++ b/core/src/main/java/de/ids_mannheim/korap/user/TokenContext.java
@@ -58,7 +58,7 @@
m.put(Attributes.TOKEN_EXPIRATION,
TimeUtils.format(this.expirationTime));
m.put(Attributes.TOKEN, this.token);
- m.put(Attributes.AUTHENTICATION_TYPE, this.authenticationType);
+ m.put(Attributes.TOKEN_TYPE, this.authenticationType);
return m;
}
diff --git a/core/src/main/java/de/ids_mannheim/korap/web/utils/KustvaktResponseHandler.java b/core/src/main/java/de/ids_mannheim/korap/web/utils/KustvaktResponseHandler.java
index 6c88743..298ee82 100644
--- a/core/src/main/java/de/ids_mannheim/korap/web/utils/KustvaktResponseHandler.java
+++ b/core/src/main/java/de/ids_mannheim/korap/web/utils/KustvaktResponseHandler.java
@@ -7,6 +7,7 @@
import javax.ws.rs.core.Response;
import de.ids_mannheim.korap.auditing.AuditRecord;
+import de.ids_mannheim.korap.config.AuthenticationType;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.exceptions.StatusCodes;
import de.ids_mannheim.korap.interfaces.db.AuditingIface;
@@ -78,21 +79,31 @@
}
+// public WebApplicationException throwAuthenticationException (String message){
+// return throwAuthenticationException(message, AuthenticationType.BASIC);
+// }
+
//todo: if exception, make exception message and error code available if not masked!
- public WebApplicationException throwAuthenticationException (String message) {
+ public WebApplicationException throwAuthenticationException (String message, AuthenticationType authType) {
return new WebApplicationException(Response
.status(Response.Status.UNAUTHORIZED)
.header(HttpHeaders.WWW_AUTHENTICATE,
- "Basic realm=Kustvakt")
+ authType.name()+" realm=\"Kustvakt\"")
.entity(buildNotification(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
"Unauthorized access", message)).build());
}
- public WebApplicationException throwAuthenticationException (KustvaktException e) {
+ public WebApplicationException throwAuthenticationException (KustvaktException e,
+ AuthenticationType authType) {
+ return throwAuthenticationException(e, authType.name());
+ }
+
+ public WebApplicationException throwAuthenticationException (KustvaktException e,
+ String authType) {
return new WebApplicationException(Response
.status(Response.Status.UNAUTHORIZED)
.header(HttpHeaders.WWW_AUTHENTICATE,
- "Basic realm=Kustvakt")
+ authType+" realm=\"Kustvakt\"")
.entity(buildNotification(e.getStatusCode(),
e.getMessage(), e.getEntity())).build());
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/framework/AuthorizationData.java b/full/src/main/java/de/ids_mannheim/korap/authentication/framework/AuthorizationData.java
index 8f310a6..13715a7 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/framework/AuthorizationData.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/framework/AuthorizationData.java
@@ -10,5 +10,7 @@
private String token;
private AuthenticationType authenticationType;
+ private String username;
+ private String password;
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/framework/HttpAuthorizationHandler.java b/full/src/main/java/de/ids_mannheim/korap/authentication/framework/HttpAuthorizationHandler.java
index b5851e3..22bd096 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/framework/HttpAuthorizationHandler.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/framework/HttpAuthorizationHandler.java
@@ -3,8 +3,6 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
-import com.sun.jersey.api.client.ClientResponse.Status;
-
import de.ids_mannheim.korap.config.AuthenticationType;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.exceptions.StatusCodes;
@@ -53,7 +51,13 @@
return data;
}
- public void parseToken (AuthorizationData data) throws KustvaktException {
- String[] credentials = transferEncoding.decodeBase64(data.getToken());
+ public AuthorizationData parseToken (AuthorizationData data) throws KustvaktException {
+ String[] credentials = transferEncoding.decodeBase64(data.getToken());
+ data.setUsername(credentials[0]);
+ data.setPassword(credentials[1]);
+ return data;
}
+
+
+
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java
index bc4f0c9..802a5b2 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java
@@ -29,7 +29,6 @@
import de.ids_mannheim.korap.authentication.framework.AuthorizationData;
import de.ids_mannheim.korap.authentication.framework.HttpAuthorizationHandler;
-import de.ids_mannheim.korap.authentication.framework.TransferEncoding;
import de.ids_mannheim.korap.config.Attributes;
import de.ids_mannheim.korap.config.AuthenticationType;
import de.ids_mannheim.korap.config.BeansFactory;
@@ -65,9 +64,6 @@
@Autowired
private HttpAuthorizationHandler authorizationHandler;
- @Autowired
- private TransferEncoding transferEncoding;
-
private static Boolean DEBUG_LOG = true;
//todo: bootstrap function to transmit certain default configuration settings and examples (example user queries,
@@ -147,11 +143,11 @@
"Authorization header"));
}
- String[] values;
+ AuthorizationData authorizationData;
try {
- AuthorizationData authorizationData = authorizationHandler.
+ authorizationData = authorizationHandler.
parseAuthorizationHeader(auth.get(0));
- values = transferEncoding.decodeBase64(authorizationData.getToken());
+ authorizationData = authorizationHandler.parseToken(authorizationData);
}
catch (KustvaktException e) {
@@ -193,12 +189,10 @@
// secCtx.isSecure() ? "yes" : "no");
} // DEBUG_LOG
- // "Invalid syntax for username and password"
- if (values == null)
- throw kustvaktResponseHandler.throwit(StatusCodes.ACCESS_DENIED);
-
- if (values[0].equalsIgnoreCase("null")
- | values[1].equalsIgnoreCase("null"))
+ if (authorizationData.getUsername() == null ||
+ authorizationData.getUsername().isEmpty() ||
+ authorizationData.getPassword()== null ||
+ authorizationData.getPassword().isEmpty())
// is actual an invalid request
throw kustvaktResponseHandler.throwit(StatusCodes.REQUEST_INVALID);
@@ -212,7 +206,7 @@
try {
// User user = controller.authenticate(0, values[0], values[1], attr); Implementation by Hanl
User user = controller.authenticate(AuthenticationType.LDAP,
- values[0], values[1], attr); // Implementation with IdM/LDAP
+ authorizationData.getUsername(), authorizationData.getPassword(), attr); // Implementation with IdM/LDAP
// Userdata data = this.controller.getUserData(user, UserDetails.class); // Implem. by Hanl
// todo: is this necessary?
// attr.putAll(data.fields());
@@ -269,28 +263,25 @@
List<String> auth =
headers.getRequestHeader(ContainerRequest.AUTHORIZATION);
- String[] values;
+ AuthorizationData authorizationData;
try {
- AuthorizationData authorizationData = authorizationHandler.
+ authorizationData = authorizationHandler.
parseAuthorizationHeader(auth.get(0));
- values = transferEncoding.decodeBase64(authorizationData.getToken());
+ authorizationData = authorizationHandler.parseToken(authorizationData);
}
catch (KustvaktException e) {
throw kustvaktResponseHandler.throwit(e);
}
- // authentication = StringUtils.stripTokenType(authentication);
- // String[] values = new String(
- // DatatypeConverter.parseBase64Binary(authentication)).split(":");
- // String[] values = Base64.base64Decode(authentication).split(":");
-
- // "Invalid syntax for username and password"
// Implementation Hanl mit '|'. 16.02.17/FB
//if (values[0].equalsIgnoreCase("null")
// | values[1].equalsIgnoreCase("null"))
- if (values[0].equalsIgnoreCase("null")
- || values[1].equalsIgnoreCase("null"))
+ if (authorizationData.getUsername() == null ||
+ authorizationData.getUsername().isEmpty() ||
+ authorizationData.getPassword()== null ||
+ authorizationData.getPassword().isEmpty())
+ // is actual an invalid request
throw kustvaktResponseHandler.throwit(StatusCodes.REQUEST_INVALID);
Map<String, Object> attr = new HashMap<>();
@@ -300,7 +291,7 @@
String contextJson;
try {
User user = controller.authenticate(AuthenticationType.SESSION,
- values[0], values[1], attr);
+ authorizationData.getUsername(), authorizationData.getPassword(), attr);
context = controller.createTokenContext(user, attr,
AuthenticationType.SESSION);
contextJson = context.toJson();
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
index 34b1875..bffe9d8 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
@@ -279,7 +279,7 @@
}
catch (KustvaktException e) {
throw kustvaktResponseHandler
- .throwAuthenticationException(ctx.getUsername());
+ .throwAuthenticationException(ctx.getUsername(), ctx.getAuthenticationType());
}
try {
return Response.ok(m.toEntity()).build();
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/filter/AdminFilter.java b/full/src/main/java/de/ids_mannheim/korap/web/filter/AdminFilter.java
index 67ff04a..12e24cd 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/filter/AdminFilter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/filter/AdminFilter.java
@@ -8,6 +8,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
+import com.ctc.wstx.util.StringUtil;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;
import com.sun.jersey.spi.container.ContainerResponseFilter;
@@ -22,6 +23,7 @@
import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
import de.ids_mannheim.korap.user.TokenContext;
import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.utils.StringUtils;
import de.ids_mannheim.korap.web.utils.KustvaktContext;
import de.ids_mannheim.korap.web.utils.KustvaktResponseHandler;
@@ -51,13 +53,13 @@
cr.getHeaderValue(ContainerRequest.AUTHORIZATION);
AuthorizationData data;
- String[] userData;
try {
data = authorizationHandler.parseAuthorizationHeader(authorization);
- userData = transferEncoding.decodeBase64(data.getToken());
+ data = authorizationHandler.parseToken(data);
}
catch (KustvaktException e) {
- throw kustvaktResponseHandler.throwAuthenticationException(e);
+ String authType = StringUtils.stripTokenType(authorization);
+ throw kustvaktResponseHandler.throwAuthenticationException(e, authType);
}
String host = cr.getHeaderValue(ContainerRequest.HOST);
@@ -68,20 +70,20 @@
try {
// EM: fix me: AuthenticationType based on header value
User user = authManager.authenticate(data.getAuthenticationType(),
- userData[0], userData[0], attributes);
+ data.getUsername(), data.getPassword(), attributes);
if (!user.isAdmin()) {
throw kustvaktResponseHandler.throwAuthenticationException(
- "Admin authentication failed.");
+ "Admin authentication failed.", data.getAuthenticationType());
}
Map<String, Object> properties = cr.getProperties();
properties.put("user", user);
}
catch (KustvaktException e) {
- throw kustvaktResponseHandler.throwAuthenticationException(e);
+ throw kustvaktResponseHandler.throwAuthenticationException(e, data.getAuthenticationType());
}
TokenContext c = new TokenContext();
- c.setUsername(userData[0]);
+ c.setUsername(data.getUsername());
c.setAuthenticationType(data.getAuthenticationType());
// EM: is this secure? Is token context not sent outside Kustvakt?
c.setToken(data.getToken());
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java b/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java
index 61f92e7..2f57c6c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java
@@ -13,8 +13,10 @@
import de.ids_mannheim.korap.authentication.framework.AuthorizationData;
import de.ids_mannheim.korap.authentication.framework.HttpAuthorizationHandler;
import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
import de.ids_mannheim.korap.user.TokenContext;
+import de.ids_mannheim.korap.utils.StringUtils;
import de.ids_mannheim.korap.web.utils.KustvaktContext;
import de.ids_mannheim.korap.web.utils.KustvaktResponseHandler;
@@ -53,16 +55,18 @@
if (authorization != null && !authorization.isEmpty()) {
TokenContext context;
+ AuthorizationData authData;
try {
- AuthorizationData data = authorizationHandler
+ authData = authorizationHandler
.parseAuthorizationHeader(authorization);
context = userController.getTokenStatus(
- data.getAuthenticationType(), data.getToken(), host,
+ authData.getAuthenticationType(), authData.getToken(), host,
ua);
}
catch (KustvaktException e) {
+ String authType = StringUtils.stripTokenType(authorization);
throw kustvaktResponseHandler
- .throwAuthenticationException(authorization);
+ .throwAuthenticationException(e, authType);
}
// fixme: give reason why access is not granted?
if (context != null && context.isValid()
@@ -70,7 +74,9 @@
| !context.isSecureRequired()))
request.setSecurityContext(new KustvaktContext(context));
else
- throw kustvaktResponseHandler.throwAuthenticationException("");
+ throw kustvaktResponseHandler.throwAuthenticationException(
+ new KustvaktException(StatusCodes.UNAUTHORIZED_OPERATION),
+ authData.getAuthenticationType());
}
return request;
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/filter/BlockingFilter.java b/full/src/main/java/de/ids_mannheim/korap/web/filter/BlockingFilter.java
index b8faf76..e0d1c02 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/filter/BlockingFilter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/filter/BlockingFilter.java
@@ -4,6 +4,9 @@
import com.sun.jersey.spi.container.ContainerRequestFilter;
import com.sun.jersey.spi.container.ContainerResponseFilter;
import com.sun.jersey.spi.container.ResourceFilter;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
import de.ids_mannheim.korap.user.TokenContext;
import de.ids_mannheim.korap.web.utils.KustvaktResponseHandler;
@@ -25,19 +28,27 @@
@Autowired
KustvaktResponseHandler kustvaktResponseHandler;
-
+
@Override
public ContainerRequest filter (ContainerRequest request) {
TokenContext context;
+
try {
context = (TokenContext) request.getUserPrincipal();
}
catch (UnsupportedOperationException e) {
- throw kustvaktResponseHandler.throwAuthenticationException("");
+ throw kustvaktResponseHandler.throwit(new KustvaktException(
+ StatusCodes.UNAUTHORIZED_OPERATION, e.getMessage(), e));
}
- if(context == null || context.isDemo())
- throw kustvaktResponseHandler.throwAuthenticationException("");
+ if (context == null || context.isDemo()) {
+ throw kustvaktResponseHandler.throwit(
+ new KustvaktException(StatusCodes.UNAUTHORIZED_OPERATION,
+ "Operation is not permitted for user: "
+ + context.getUsername(),
+ context.getUsername()));
+ }
+
return request;
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/filter/NonDemoBlockingFilter.java b/full/src/main/java/de/ids_mannheim/korap/web/filter/NonDemoBlockingFilter.java
index 95cb077..e5fa7f1 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/filter/NonDemoBlockingFilter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/filter/NonDemoBlockingFilter.java
@@ -4,6 +4,9 @@
import com.sun.jersey.spi.container.ContainerRequestFilter;
import com.sun.jersey.spi.container.ContainerResponseFilter;
import com.sun.jersey.spi.container.ResourceFilter;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
import de.ids_mannheim.korap.user.TokenContext;
import de.ids_mannheim.korap.web.utils.KustvaktResponseHandler;
@@ -34,13 +37,14 @@
context = (TokenContext) request.getUserPrincipal();
}
catch (UnsupportedOperationException e) {
- throw kustvaktResponseHandler.throwAuthenticationException("");
+ throw kustvaktResponseHandler.throwit(new KustvaktException(
+ StatusCodes.UNAUTHORIZED_OPERATION, e.getMessage(), e));
}
- if (context == null || context.isDemo())
- throw kustvaktResponseHandler
- .throwAuthenticationException("Service not available for non-authenticated "
- + "or demo account users!");
+ if (context == null || context.isDemo()){
+ new KustvaktException(StatusCodes.UNAUTHORIZED_OPERATION,
+ "Operation is not permitted for guest users");
+ }
return request;
}
diff --git a/full/src/main/resources/log4j.properties b/full/src/main/resources/log4j.properties
index 35aad91..308c9ca 100644
--- a/full/src/main/resources/log4j.properties
+++ b/full/src/main/resources/log4j.properties
@@ -4,8 +4,9 @@
log4j.rootLogger=ERROR, stdout, debugLog
log4j.logger.log=ERROR, errorLog
-log4j.logger.de.ids_mannheim.korap.service.VirtualCorpusService = error, debugLog
-log4j.logger.de.ids_mannheim.korap.web.SearchKrill = debug, debugLog, stdout
+#log4j.logger.de.ids_mannheim.korap.service.VirtualCorpusService = error, debugLog
+#log4j.logger.de.ids_mannheim.korap.web.controller.AuthenticationController = debug, debugLog, stdout
+
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java b/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java
index 1a26e1c..71a425a 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java
@@ -3,13 +3,17 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
import org.eclipse.jetty.http.HttpHeaders;
-import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.databind.JsonNode;
import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.spi.container.ContainerRequest;
import de.ids_mannheim.korap.authentication.framework.HttpAuthorizationHandler;
import de.ids_mannheim.korap.config.Attributes;
@@ -25,7 +29,7 @@
HttpAuthorizationHandler handler;
@Test
- @Ignore
+// @Ignore
public void testStoreVC () throws KustvaktException {
String json =
"{\"name\": \"new vc\",\"type\": \"PRIVATE\",\"createdBy\": "
@@ -49,8 +53,17 @@
ClientResponse response = resource().path("vc").path("store")
.entity(json).post(ClientResponse.class);
+
+ Set<Entry<String, List<String>>> headers = response.getHeaders().entrySet();
+
+ for (Entry<String, List<String>> header: headers){
+ if (header.getKey().equals(ContainerRequest.WWW_AUTHENTICATE)){
+ assertEquals("Basic realm=\"Kustvakt\"", header.getValue().get(0));
+ }
+ }
+// System.out.println(header);
+
String entity = response.getEntity(String.class);
-
JsonNode node = JsonUtils.readTree(entity);
assertEquals(StatusCodes.UNAUTHORIZED_OPERATION,
node.at("/errors/0/0").asInt());