Commit d9c5f3e7 by amir

1.3.0:

- add service authorization with jwt
- env param override config file
parent dd09e0a5
### Microservice Framework in JAVA
## 1.3.0:
- add service authorization with jwt
- env param override config file
## 1.2.5:
- support rabbit on server side
......@@ -26,3 +29,6 @@
of the dest service
# Env for service discovery:
service.resolver.polling.interval (milli) default is 5000
# Env for jwt:
jwt.token.in.authorization : true
jwt.salt : "12345678901234567890123456789012"
group 'com.ipgallery.common'
version '1.2.5'
version '1.3.0'
apply plugin: 'java'
apply plugin: 'maven-publish'
......@@ -12,9 +12,9 @@ sourceCompatibility = 1.8
repositories {
//use mavenLocal in cases you want to create this jar on your local machine
//or to be able to use one
// mavenLocal()//defaults to ~/.m2/repository
mavenLocal()//defaults to ~/.m2/repository
maven { url "http://172.16.1.132:8081/repository/internal" }
maven { url "http://mandubian-mvn.googlecode.com/svn/trunk/mandubian-mvn/repository" }
}
dependencies {
......@@ -26,11 +26,12 @@ dependencies {
compile 'com.netflix.hystrix:hystrix-metrics-event-stream:1.4.12'
compile 'redis.clients:jedis:2.4.2'
compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.0.2'
compile 'com.ipgallery.common:utils:1.1.3'
compile 'com.ipgallery.common:utils:1.1.4'
compile ('com.ipgallery.common:rabbitmq:1.0.2')
compile 'com.ecwid.consul:consul-api:1.1.9'
compile 'com.github.davidb:metrics-influxdb:0.8.2'
compile 'io.dropwizard.metrics:metrics-graphite:3.1.2'
compile 'io.jsonwebtoken:jjwt:0.6.0'
testCompile group: 'junit', name: 'junit', version: '4.11'
}
......
......@@ -71,6 +71,7 @@ public class MicroserviceApp
ILogger logger = null;
IPubSub pubSubClient = null;
boolean enableMetrics = false;
boolean enableDefaultServiceAuthorization = false;
IServiceDiscovery serviceDiscovery = null;
IConfiguration configuration = null;
Map<String, microservice.MicroserviceClient> msClientMap = null;
......@@ -105,6 +106,11 @@ public class MicroserviceApp
}
public static MicroserviceApp getsInstance() { return sInstance; }
public String getAppName() {
return appName;
}
/*************************
* WITH SECTION
*************************/
......@@ -156,7 +162,12 @@ public class MicroserviceApp
this.addHandler(MON_PREFIX, optMonitorHandler.get());
return this;
}
public MicroserviceApp withDefaultServiceAuthorization() {
this.enableDefaultServiceAuthorization = true;
return this;
}
/*************************************************
* ADD SECTION
**************************************************/
......@@ -183,6 +194,8 @@ public class MicroserviceApp
{
if (msMap == null)
msMap = new HashMap<String, BaseHandler>();
if (enableDefaultServiceAuthorization && handler.getAuthType().equals(BaseHandler.EnumAuthenticationType.DEFAULT))
handler.setAuthType(BaseHandler.EnumAuthenticationType.JWT);
msMap.put(prefix, handler);
}
return this;
......
......@@ -5,9 +5,11 @@ import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import microservice.defs.Enums;
import microservice.io.iface.IContainer;
import microservice.io.iface.IRequest;
import microservice.io.iface.IResponse;
import microservice.types.UserProfile;
public class RequestContext
......@@ -22,7 +24,9 @@ public class RequestContext
public IRequest request;
public ObjectMapper objMapper;
public String rcid; // request correlation id
public UserProfile userProfile;
public Enums.EnumCrudMethod enumCrudMethod;
public String getParameter(String paramName) {
if (queryParameters != null && queryParameters.containsKey(paramName))
......
......@@ -9,4 +9,11 @@ public class Constants
public static final String METHOD_NOT_IMPLEMENTED = "method not implemented";
public static final String FAILED_TO_GET_PARAMS = "failed to get params";
public static final String RCID_HEADER = "X-RCID";
public static final String JWT_TOKEN = "jwtToken";
public static final String NO_TOKEN_FOR_REQUEST = "no token for request";
public static final String TOKEN_EXPIRED = "token expired";
public static final String METHOD_NOT_AUTHORIZED = "service/method not authorized";
public static final String INVALID_REQUEST_TOKEN = "invalid request/token";
public static final String AUTHORIZATION_HEADER = "Authorization";
}
......@@ -43,7 +43,25 @@ public class Enums
E_READ,
E_UPDATE,
E_DELETE;
public static EnumCrudMethod resolveMethodFromHttp(EnumHttpMethod enumHttpMethod){
EnumCrudMethod enumCrudMethod= null;
switch (enumHttpMethod){
case E_GET:
enumCrudMethod = EnumCrudMethod.E_READ;
break;
case E_POST:
enumCrudMethod = EnumCrudMethod.E_CREATE;
break;
case E_PUT:
enumCrudMethod = EnumCrudMethod.E_UPDATE;
break;
case E_DELETE:
enumCrudMethod = EnumCrudMethod.E_DELETE;
break;
}
return enumCrudMethod;
}
}
public enum EnumProtocol
......
......@@ -14,11 +14,22 @@ import microservice.io.iface.INotifyCallback;
public abstract class BaseHandler
{
public enum EnumAuthenticationType {
DEFAULT,
NONE,
JWT,
FORM
}
protected ObjectMapper objMapper = null;
protected ILogger logger = null;
protected Optional<IContainer> optContainer = Optional.empty();
protected Optional<IConfiguration> optConfiguration = Optional.empty();
protected MicroserviceApp msApp = null;
protected EnumAuthenticationType authType = EnumAuthenticationType.DEFAULT;
/*
* SOME HELPERS
*/
......@@ -27,6 +38,12 @@ public abstract class BaseHandler
return objMapper;
}
public EnumAuthenticationType getAuthType() {
return authType;
}
public void setAuthType(EnumAuthenticationType authType) {
this.authType = authType;
}
public void setObjMapper(ObjectMapper objMapper){
this.objMapper = objMapper;
......
package microservice.handlers;
import com.eaio.uuid.UUID;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.HeaderMap;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import microservice.MicroserviceApp;
import microservice.RequestContext;
import microservice.common.EncryptionUtils;
import microservice.defs.Constants;
import microservice.defs.Enums;
import microservice.defs.Enums.EnumHttpMethod;
import microservice.io.iface.IContainer;
import microservice.io.iface.IMetricsFactory;
import microservice.io.iface.*;
import microservice.io.iface.IMetricsFactory.IMeter;
import microservice.io.iface.IMetricsFactory.ITimer;
import microservice.io.iface.INotifyCallback;
import microservice.io.iface.IPubSub;
import microservice.io.iface.IRequest;
import microservice.io.iface.IResponse;
import microservice.io.impl.IMetricsFactoryImpl;
import microservice.io.impl.IRequestRestImpl;
import microservice.io.impl.IResponseRestImpl;
import com.eaio.uuid.UUID;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import microservice.types.BaseRestResponse;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import microservice.types.UserProfile;
import static microservice.defs.Constants.*;
public class RestHandler implements HttpHandler , IContainer
{
......@@ -39,7 +41,9 @@ public class RestHandler implements HttpHandler , IContainer
ITimer getTimer = null;
ITimer postTimer = null;
boolean enableMetrics = false;
private static boolean jwtTokenInAuthorization = Boolean.valueOf(System.getProperty("jwt.token.in.authorization","true")).booleanValue();
String appName = null;
public RestHandler(String apiContextPath,BaseHandler msHandler, IPubSub pubSub, boolean enableMetrics)
{
super();
......@@ -52,6 +56,7 @@ public class RestHandler implements HttpHandler , IContainer
this.enableMetrics = enableMetrics;
if (this.enableMetrics)
createMetrics();
appName = MicroserviceApp.getsInstance().getAppName();
}
......@@ -85,36 +90,38 @@ public class RestHandler implements HttpHandler , IContainer
{
HttpString requestMethod = exchange.getRequestMethod();
EnumHttpMethod eMethod = EnumHttpMethod.resolveMethod(requestMethod.toString());
reqContext.enumCrudMethod = Enums.EnumCrudMethod.resolveMethodFromHttp(eMethod);
//exchange. request.setCharacterEncoding(Constants.C_ENCODING_UTF8);
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, Constants.CONTENT_TYPE_JSON);
if (eMethod != null && reqContext != null)
{
// pre
if (enableMetrics)
preHandleMetrics(eMethod);
switch (eMethod)
{
case E_DELETE:
doDelete(reqContext);
break;
case E_GET:
doGet(reqContext);
break;
case E_POST:
doPost(reqContext);
break;
case E_PUT:
doPut(reqContext);
break;
default:
break;
if (validateRequest(reqContext)) {
// pre
if (enableMetrics)
preHandleMetrics(eMethod);
switch (eMethod) {
case E_DELETE:
doDelete(reqContext);
break;
case E_GET:
doGet(reqContext);
break;
case E_POST:
doPost(reqContext);
break;
case E_PUT:
doPut(reqContext);
break;
default:
break;
}
// post
if (enableMetrics)
postHandleMetrics(eMethod);
}
// post
if (enableMetrics)
postHandleMetrics(eMethod);
}
else
{
......@@ -133,6 +140,76 @@ public class RestHandler implements HttpHandler , IContainer
//exchange.endExchange();
}
/**
* validate the request: service authorization etc.
* @param requestContext
* @return
*/
private boolean validateRequest(RequestContext requestContext)
{
boolean valid = true;
if (msHandler.getAuthType().equals(BaseHandler.EnumAuthenticationType.JWT)){
// get token
String token = getJwtToken(requestContext);
if (token != null)
{
try {
Claims claims = EncryptionUtils.parseJWT(token);
if(claims != null) {
// resolve service authorization
UserProfile up = new UserProfile(claims);
// resolve authorization
valid = up.isServiceAuthorized(appName, requestContext.enumCrudMethod);
if (valid) {
// set user profile
requestContext.userProfile = up;
} else {
sendErrorResp(requestContext.response, METHOD_NOT_AUTHORIZED);
}
}
else {
sendErrorResp(requestContext.response,Constants.INVALID_REQUEST_TOKEN);
}
} catch (ExpiredJwtException exception){
sendErrorResp(requestContext.response,TOKEN_EXPIRED);
valid = false;
}
}
else
{
MicroserviceApp.getsInstance().getLogger().error(NO_TOKEN_FOR_REQUEST);
sendErrorResp(requestContext.response,NO_TOKEN_FOR_REQUEST);
valid = false;
}
}
return valid;
}
private String getJwtToken(RequestContext requestContext) {
String jwt = null;
/*
* jwt token
*/
if (jwtTokenInAuthorization)
{
String authValue = requestContext.request.getFirstHeader(Constants.AUTHORIZATION_HEADER);
if(authValue != null)
{
// "Bearer <token>"
String[] strings = spaceSeperatorPattern.split(authValue);
if(strings.length > 1)
jwt = strings[1];
}
}
else
{
// url - param
jwt =requestContext.getParameter(JWT_TOKEN);
}
return jwt;
}
private void preHandleMetrics(EnumHttpMethod eMethod)
{
switch (eMethod)
......@@ -194,7 +271,7 @@ public class RestHandler implements HttpHandler , IContainer
*/
String relativePath = exchange.getRelativePath();
if (relativePath != null && relativePath.length() > 1)
reqCtx.params = seperatorPattern.split(relativePath.substring(1));
reqCtx.params = slashSeperatorPattern.split(relativePath.substring(1));
String queryString = exchange.getQueryString();
if (queryString != null && !queryString.isEmpty())
{
......@@ -203,10 +280,11 @@ public class RestHandler implements HttpHandler , IContainer
/*
* rcid
*/
reqCtx.rcid = exchange.getRequestHeaders().getFirst(Constants.RCID_HEADER);
HeaderMap requestHeaders = exchange.getRequestHeaders();
reqCtx.rcid = requestHeaders.getFirst(Constants.RCID_HEADER);
if (reqCtx.rcid == null) // create a new one
reqCtx.rcid = new UUID().toString();
return reqCtx;
}
......
......@@ -16,7 +16,8 @@ import microservice.handlers.BaseHandler;
*/
public interface IContainer
{
public static Pattern seperatorPattern = Pattern.compile("/");
public static Pattern slashSeperatorPattern = Pattern.compile("/");
public static Pattern spaceSeperatorPattern = Pattern.compile(" ");
public void sendErrorResp(IResponse response, String error);
......
package microservice.io.iface;
import java.io.InputStream;
import java.util.List;
public interface IRequest
{
......@@ -8,4 +9,19 @@ public interface IRequest
InputStream getInputStream();
String getQueryString();
String getRelativePath();
/**
* getting the first header value if there are more
* then the same header
* @param headerName
* @return
*/
String getFirstHeader(String headerName);
/**
* getting all the header values
* @param headerName
* @return list of the header values
*/
List<String> getHeader(String headerName);
}
......@@ -2,6 +2,7 @@ package microservice.io.impl;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
//import com.sun.xml.internal.ws.api.message.stream.InputStreamMessage;
......@@ -47,6 +48,16 @@ public class IRequestMBIImpl implements IRequest
{
return rmqRequest.getParameterByName(RMQRestRequest.PARAMS);
}
@Override
public String getFirstHeader(String headerName) {
return null;
}
@Override
public List<String> getHeader(String headerName) {
return null;
}
}
package microservice.io.impl;
import java.io.InputStream;
import java.util.List;
import io.undertow.server.HttpServerExchange;
import microservice.io.iface.IRequest;
......@@ -36,6 +37,16 @@ public class IRequestRestImpl implements IRequest
{
return exchange.getRelativePath();
}
@Override
public String getFirstHeader(String headerName) {
return exchange.getRequestHeaders().getFirst(headerName);
}
@Override
public List<String> getHeader(String headerName) {
return exchange.getRequestHeaders().get(headerName);
}
}
......@@ -12,6 +12,7 @@ public class TestConfiguration {
@Test
public void testConfProviderConsulImpl()
{
System.setProperty("configFile.location","/opt/mcx/config/config.properties");
IServiceDiscoveryConsulImpl iServiceDiscovery = new IServiceDiscoveryConsulImpl("localhost",8500);
iServiceDiscovery.registerService("myService", "2", "1.2.3.4", 32002);
IConfiguration config = new IConfigurationConfigPropImpl();
......@@ -20,4 +21,5 @@ public class TestConfiguration {
Object value1 = config.getString("key1",null);
System.out.println(value1);
}
}
......@@ -30,11 +30,11 @@ public class TestMicroserviceApp {
//ILogger logger = new ILogger4jImpl(appName);
microservice.MicroserviceApp msApp = new microservice.MicroserviceApp(appName);
msApp.withMetrics()
//.withLogger(logger)
.withMonitoring()
.withPubSub(new microservice.io.impl.IPubSubMQTTImpl("tcp://localhost",0,null,0))
//.withServiceDiscovery(serDisco)
.addHandler("/test",new TestMicroserviceHandler())
.withDefaultServiceAuthorization()
.withPubSub(new microservice.io.impl.IPubSubMQTTImpl("tcp://localhost",0,null,0))
.withServiceDiscovery(serDisco)
.withMonitoring()
// .addHandler("/test",new TestMicroserviceHandler())
.addMicroserviceClient(new MicroserviceClient(cmdClient,clientParams))
//.addMicroserviceClient("rabbit-service",new MicroserviceClient(EnumRestClientType.E_RABBITMQ,clientParams))
.addRestServer(new IRestServerUndertowImpl(new RestServerParams(32000, "localhost", 2)))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment