diff --git a/config-layers/common/in/erail/common/FrameworkConfiguration.properties b/config-layers/common/in/erail/common/FrameworkConfiguration.properties index aba2773..c3811db 100644 --- a/config-layers/common/in/erail/common/FrameworkConfiguration.properties +++ b/config-layers/common/in/erail/common/FrameworkConfiguration.properties @@ -3,4 +3,3 @@ $class=in.erail.common.FrameworkConfiguration $scope=GLOBAL redisClient=/io/vertx/redis/RedisClient -oAuth2Auth=/io/vertx/ext/auth/oauth2/OAuth2Auth diff --git a/config-layers/common/in/erail/route/CORSRouteBuilder.properties b/config-layers/common/in/erail/route/CORSRouteBuilder.properties index 2170281..b80051e 100644 --- a/config-layers/common/in/erail/route/CORSRouteBuilder.properties +++ b/config-layers/common/in/erail/route/CORSRouteBuilder.properties @@ -6,7 +6,7 @@ log=true enable=true allowedOrigin=* -allowedMethod=GET,POST,OPTIONS +allowedMethod=DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT allowedCredentials=false maxAgeSeconds=86400 -allowedHeaders= +allowedHeaders=Content-Type,Cache-Control,Authorization diff --git a/config-layers/common/in/erail/route/LoadUserFromAccessTokenRouteBuilder.properties b/config-layers/common/in/erail/route/LoadUserFromAccessTokenRouteBuilder.properties index cc19a08..4f6b6c0 100644 --- a/config-layers/common/in/erail/route/LoadUserFromAccessTokenRouteBuilder.properties +++ b/config-layers/common/in/erail/route/LoadUserFromAccessTokenRouteBuilder.properties @@ -2,6 +2,5 @@ $class=in.erail.route.LoadUserFromAccessTokenRouteBuillder vertx=/io/vertx/core/Vertx +authProvider=/io/vertx/ext/auth/jwt/JWTAuth log=true -oAuth2Auth=/io/vertx/ext/auth/oauth2/OAuth2Auth -enable^=/in/erail/common/FrameworkConfiguration.oAuth2AuthEnable diff --git a/config-layers/common/io/vertx/ext/auth/jwt/JWTAuth.properties b/config-layers/common/io/vertx/ext/auth/jwt/JWTAuth.properties new file mode 100644 index 0000000..0ce3cff --- /dev/null +++ b/config-layers/common/io/vertx/ext/auth/jwt/JWTAuth.properties @@ -0,0 +1,8 @@ +#/io/vertx/ext/auth/jwt/JWTAuth +$class=io.vertx.reactivex.ext.auth.jwt.JWTAuth +$instanceFactory=/in/erail/factory/MethodInstanceFactory +$factory.class=io.vertx.reactivex.ext.auth.jwt.JWTAuth +$factory.method.name=create +$factory.param.values=/io/vertx/core/Vertx,/io/vertx/ext/auth/jwt/JWTAuthOptions +$factory.param.type=io.vertx.reactivex.core.Vertx,io.vertx.ext.auth.jwt.JWTAuthOptions +$factory.enable=true diff --git a/config-layers/common/io/vertx/ext/auth/jwt/JWTAuthOptions.properties b/config-layers/common/io/vertx/ext/auth/jwt/JWTAuthOptions.properties new file mode 100644 index 0000000..86815ac --- /dev/null +++ b/config-layers/common/io/vertx/ext/auth/jwt/JWTAuthOptions.properties @@ -0,0 +1,5 @@ +#/io/vertx/ext/auth/jwt/JWTAuthOptions +$class=io.vertx.ext.auth.jwt.JWTAuthOptions +$instanceFactory=/in/erail/factory/ParameterConstructorInstanceFactory +$constructor.param.values=jwtAuthOptionsConfig.json +$constructor.param.type=io.vertx.core.json.JsonObject diff --git a/config-layers/common/io/vertx/ext/auth/jwt/jwtAuthOptionsConfig.json b/config-layers/common/io/vertx/ext/auth/jwt/jwtAuthOptionsConfig.json new file mode 100644 index 0000000..abe9308 --- /dev/null +++ b/config-layers/common/io/vertx/ext/auth/jwt/jwtAuthOptionsConfig.json @@ -0,0 +1,10 @@ +{ + "pubSecKeys" : [ + { + "algorithm" : "RS256", + "publicKey" : "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr1MjI2WAw06VK8biQPC+0mVOkI4ZRt+327fxwrxyuu32AMPKznPCsKtRaI/Xma3+Yi09Dt99agkfUfw/rPr3N0Vcgzd1muhqZOe6vfWqmPCUUB263EkSa1GIx4pLZ3CfvAc3f24Y00CS+S0gjCIr7lwLelcL9Hu9eZg5sTEfzKB/3+yUJ875aYRGWXdM7DnNzODXKa9kc1EqWjwprX0UZwoo3OycgmYS+DyI/MHPcdWbilsjsw77ISFeBZ7OZ+hFJ/baABenAnsTwqbyvWlC6TS3GCXTeH10+0RGWvjJAZEPX0PEt626iMTqP61XEh8kpOROU/xmLWTKHz3EAcX+4QIDAQAB", + "secretKey" : "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCvUyMjZYDDTpUrxuJA8L7SZU6QjhlG37fbt/HCvHK67fYAw8rOc8Kwq1Foj9eZrf5iLT0O331qCR9R/D+s+vc3RVyDN3Wa6Gpk57q99aqY8JRQHbrcSRJrUYjHiktncJ+8Bzd/bhjTQJL5LSCMIivuXAt6Vwv0e715mDmxMR/MoH/f7JQnzvlphEZZd0zsOc3M4Ncpr2RzUSpaPCmtfRRnCijc7JyCZhL4PIj8wc9x1ZuKWyOzDvshIV4Fns5n6EUn9toAF6cCexPCpvK9aULpNLcYJdN4fXT7REZa+MkBkQ9fQ8S3rbqIxOo/rVcSHySk5E5T/GYtZMofPcQBxf7hAgMBAAECggEAGOlXNNBXW2jvCSlZPKD4fCyo3SFTth5ToYShdWoRYz4sli87wdnw7+lnx9Oobs2qN4j2BAb9avOg36VX5txCBDh2zK40p64eb/f9MMCXXOPSLxAKXQKE+3q6VJ/x1uDJ0Y209QZPwLSMLZub5E12sIejmd6EdFigs4ZNrD+upQRs6laM3EJdOqrHfArh18dJQoJcq3VfCCw1p+iPOJSVC6TS6Qp8nR/Qq2h5/5DnUj68RMg6jBLuaq+2vAvS/PXkUV5L0rJT11CoPzxusDDSJl7tkxI9Uzz7RfyZFzibxAmrUIxfqFIhQq+EnycYfKuTRDIZjYXvoKqatLhKtgkXgQKBgQDa2SGZJj6HmR25B4+xmJqpf9B1cM4yz4nOUy7xA80V5DRg/qol+T3SDjPXvoinR+fdgpqUBCxVyQHRWs05fDW/xkBXxalODlNSBWwhFBO2dvbdz3xWLDZJmm6rhgo7GZplTWEL6lxxNTwiKdkCLgW2CHkDpKxPy3x3P/50fM98MwKBgQDNFohdBKoiuG2H2qML27pifgJUJXg33YgUN3xPgR2V0UyVV7u1qq9aHiBL2oO+gp1Jz1N+aQQ6FVDGZ+Okg6VKPZKEZnfYP7AgUAPkqxtsI3oAYGt1OtcLoGXns+U8LxJkuwV3IilvdkMVGQa0rXHYn8pdK149yd+nWCCJL/cEmwKBgQCsL0fzAhcSgtLS4HMbDPEqyQhPTli9u3I2JlZ5hD8YqTrY0aU3SVltaoU5ioxj6Pwx2O8b5Aip2gOXHzT2tJZpc2buZ/MkGbtOfjur7urvlbv3mqa9+f0gfePzCfwEsck7SN1BDbx7yaGtU3WM9H7D0Pi9eBOmmHguLuhZ6FUq5wKBgEbjm/zzCM/5ibqkwyjtKW6z+aAWV4iP5WJ/j1N34L8RWnRgn/x6ZCQ1N5qgjFtEkJObu1N9fz2IcqQx8sjBzFduEv/63z/7O6jfn4jh8Bef56LLsTkTPpPBPJgrYXg9GRGCZ7A3ObVSXnuja+L19N0Y1nz/6ZJX/hu85Xol/y8zAoGBAJQw/0mEww+c2YOcNiTyPOWrJ6YYtVDoi2noESgQzfcRx2YbFjkVYK1ig+rk6oMBGQt2hTCXqv7f7HWtfJ39DZ8+nIWqMEt87O7YW1A/Lmq7nFpqqGA3W5o2w+bCaMqHypL1RZo3fwNK3dXGlWOC419oXmR0yMmpjnGH3f2MFa41" + } + + ] +} \ No newline at end of file diff --git a/src/main/java/in/erail/common/FrameworkConfiguration.java b/src/main/java/in/erail/common/FrameworkConfiguration.java index f760df2..54d1bdd 100644 --- a/src/main/java/in/erail/common/FrameworkConfiguration.java +++ b/src/main/java/in/erail/common/FrameworkConfiguration.java @@ -1,6 +1,5 @@ package in.erail.common; -import io.vertx.reactivex.ext.auth.oauth2.OAuth2Auth; import io.vertx.reactivex.redis.RedisClient; import java.util.Optional; @@ -11,7 +10,6 @@ public class FrameworkConfiguration { private RedisClient mRedisClient; - private OAuth2Auth mOAuth2Auth; public RedisClient getRedisClient() { return mRedisClient; @@ -21,20 +19,8 @@ public void setRedisClient(RedisClient pRedisClient) { this.mRedisClient = pRedisClient; } - public OAuth2Auth getOAuth2Auth() { - return mOAuth2Auth; - } - - public void setOAuth2Auth(OAuth2Auth pOAuth2Auth) { - this.mOAuth2Auth = pOAuth2Auth; - } - - public boolean isRedisEnable(){ return Optional.ofNullable(getRedisClient()).isPresent(); } - public boolean isOAuth2AuthEnable(){ - return Optional.ofNullable(getOAuth2Auth()).isPresent(); - } } diff --git a/src/main/java/in/erail/model/RequestEvent.java b/src/main/java/in/erail/model/RequestEvent.java index 9a9cf7d..d6d828b 100644 --- a/src/main/java/in/erail/model/RequestEvent.java +++ b/src/main/java/in/erail/model/RequestEvent.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.google.common.io.BaseEncoding; import io.vertx.core.http.HttpMethod; +import io.vertx.core.json.JsonObject; import java.util.Map; /** @@ -23,9 +24,10 @@ public class RequestEvent { private Map mPathParameters; private Map mStageVariables; @SuppressWarnings("rawtypes") - private Map mRequestContext; + private Map mRequestContext; private byte[] mBody = new byte[0]; private boolean mIsBase64Encoded = false; + private Map mPrincipal; public String getResource() { return mResource; @@ -100,12 +102,12 @@ public void setStageVariables(Map pStageVariables) { } @SuppressWarnings("rawtypes") - public Map getRequestContext() { + public Map getRequestContext() { return mRequestContext; } @SuppressWarnings("rawtypes") - public void setRequestContext(Map pRequestContext) { + public void setRequestContext(Map pRequestContext) { this.mRequestContext = pRequestContext; } @@ -124,11 +126,25 @@ public byte[] getBody() { public void setBody(byte[] pBody) { this.mBody = pBody; } - - public String bodyAsString(){ - if(isIsBase64Encoded()){ + + public String bodyAsString() { + if (isIsBase64Encoded()) { return new String(BaseEncoding.base64().decode(new String(getBody()))); } return new String(getBody()); } + + public Map getPrincipal() { + return mPrincipal; + } + + public void setPrincipal(Map pPrincipal) { + this.mPrincipal = pPrincipal; + } + + @Override + public String toString() { + return JsonObject.mapFrom(this).toString(); + } + } diff --git a/src/main/java/in/erail/model/ResponseEvent.java b/src/main/java/in/erail/model/ResponseEvent.java index 9f16d60..3151388 100644 --- a/src/main/java/in/erail/model/ResponseEvent.java +++ b/src/main/java/in/erail/model/ResponseEvent.java @@ -3,6 +3,7 @@ import com.google.common.base.Preconditions; import com.google.common.net.HttpHeaders; import com.google.common.net.MediaType; +import io.vertx.core.json.JsonObject; import io.vertx.reactivex.core.MultiMap; import java.util.Arrays; import java.util.Collections; @@ -161,22 +162,28 @@ public ResponseEvent setContentType(String pContentType) { return this; } - public ResponseEvent setContentType(MediaType pMediaType) { - setContentType(pMediaType.toString()); - return this; - } - - public ResponseEvent addHeader(String pHeaderName, String pMediaType) { - mMultiValueHeaders.add(HttpHeaders.CONTENT_TYPE, pMediaType); + /** + * Predefined Content Type + * @param pMediaType + * @return Response Event + */ + public ResponseEvent setMediaType(MediaType pMediaType) { + ResponseEvent.this.setContentType(pMediaType.toString()); return this; } - public ResponseEvent addHeader(String pHeaderName, MediaType pMediaType) { - addHeader(HttpHeaders.CONTENT_TYPE, pMediaType.toString()); + public ResponseEvent addHeader(String pHeaderName, String pValue) { + mMultiValueHeaders.add(pHeaderName, pValue); return this; } public String headerValue(String pHeaderName) { return mMultiValueHeaders.get(pHeaderName); } + + @Override + public String toString() { + return JsonObject.mapFrom(this).toString(); + } + } diff --git a/src/main/java/in/erail/route/LoadUserFromAccessTokenRouteBuillder.java b/src/main/java/in/erail/route/LoadUserFromAccessTokenRouteBuillder.java index d0abb91..0bfe043 100644 --- a/src/main/java/in/erail/route/LoadUserFromAccessTokenRouteBuillder.java +++ b/src/main/java/in/erail/route/LoadUserFromAccessTokenRouteBuillder.java @@ -3,12 +3,11 @@ import com.google.common.base.Strings; import com.google.common.net.HttpHeaders; import io.vertx.core.json.JsonObject; -import io.vertx.ext.auth.oauth2.impl.OAuth2AuthProviderImpl; -import io.vertx.ext.auth.oauth2.impl.OAuth2TokenImpl; -import io.vertx.reactivex.ext.auth.oauth2.AccessToken; -import io.vertx.reactivex.ext.auth.oauth2.OAuth2Auth; +import io.vertx.reactivex.ext.auth.AuthProvider; import io.vertx.reactivex.ext.web.Router; import io.vertx.reactivex.ext.web.RoutingContext; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @@ -16,41 +15,48 @@ */ public class LoadUserFromAccessTokenRouteBuillder extends AbstractRouterBuilderImpl { - private OAuth2Auth mOAuth2Auth; - - public OAuth2Auth getOAuth2Auth() { - return mOAuth2Auth; - } - - public void setOAuth2Auth(OAuth2Auth pOAuth2Auth) { - this.mOAuth2Auth = pOAuth2Auth; - } + private final Pattern AUTH_TOKEN = Pattern.compile("^Bearer\\s(?.*)"); + private AuthProvider mAuthProvider; @Override public Router getRouter(Router pRouter) { pRouter.route().handler(this::handle); return pRouter; - } public void handle(RoutingContext pRoutingContext) { - + if (pRoutingContext.user() == null) { String access_token = pRoutingContext.request().getHeader(HttpHeaders.AUTHORIZATION); if (!Strings.isNullOrEmpty(access_token)) { - OAuth2AuthProviderImpl provider = (OAuth2AuthProviderImpl) getOAuth2Auth().getDelegate(); - JsonObject accessToken = new JsonObject().put("access_token", access_token.split(" ")[1]); - try { - OAuth2TokenImpl token = new OAuth2TokenImpl(provider, accessToken); - pRoutingContext.setUser(new AccessToken(token)); - } catch (RuntimeException e) { - getLog().error(e); - pRoutingContext.fail(401); - return; + Matcher tokenRegex = AUTH_TOKEN.matcher(access_token); + if (tokenRegex.find()) { + String token = tokenRegex.group("token"); + JsonObject authInfo = new JsonObject() + .put("access_token", token) + .put("token_type", "Bearer") + .put("jwt", token); + try { + pRoutingContext.setUser(getAuthProvider().rxAuthenticate(authInfo).blockingGet()); + } catch (RuntimeException e) { + getLog().error(e); + pRoutingContext.fail(401); + return; + } + } else { + getLog().warn(() -> "Invalid Auth Header:" + access_token); } } } pRoutingContext.next(); } + public AuthProvider getAuthProvider() { + return mAuthProvider; + } + + public void setAuthProvider(AuthProvider pAuthProvider) { + this.mAuthProvider = pAuthProvider; + } + } diff --git a/src/main/java/in/erail/route/OpenAPI3RouteBuilder.java b/src/main/java/in/erail/route/OpenAPI3RouteBuilder.java index 3ec4254..7d9942c 100644 --- a/src/main/java/in/erail/route/OpenAPI3RouteBuilder.java +++ b/src/main/java/in/erail/route/OpenAPI3RouteBuilder.java @@ -30,6 +30,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Optional; +import org.apache.commons.lang3.exception.ExceptionUtils; /** * @@ -37,7 +38,6 @@ */ public class OpenAPI3RouteBuilder extends AbstractRouterBuilderImpl { - private static final String AUTHORIZATION_PREFIX = "realm"; private static final String FAIL_SUFFIX = ".fail"; private RESTService[] mServices; private File mOpenAPI3File; @@ -126,6 +126,13 @@ public JsonObject serialiseRoutingContext(RoutingContext pContext) { request.setQueryStringParameters(convertMultiMapIntoMap(pContext.queryParams())); request.setPathParameters(convertMultiMapIntoMap(pContext.request().params())); + JsonObject principal = Optional + .ofNullable(pContext.user()) + .flatMap((t) -> Optional.ofNullable(t.principal())) + .orElse(new JsonObject()); + + request.setPrincipal(principal.getMap()); + JsonObject result = JsonObject.mapFrom(request); getLog().debug(() -> "Context to JSON:" + result.toString()); @@ -147,8 +154,8 @@ public HttpServerResponse buildResponseFromReply(JsonObject pReplyResponse, Rout Optional contentType = Optional.ofNullable(response.headerValue(HttpHeaders.CONTENT_TYPE)); - if (contentType.isPresent()) { - response.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.OCTET_STREAM); + if (!contentType.isPresent()) { + response.setMediaType(MediaType.OCTET_STREAM); } response @@ -183,12 +190,14 @@ public HttpServerResponse buildResponseFromReply(JsonObject pReplyResponse, Rout .filter(t -> t.isPresent()) .forEach(t -> pContext.addCookie(t.get())); - Optional body = Optional.ofNullable(response.getBody()); + Optional body = Optional + .ofNullable(response.getBody()); body.ifPresent((t) -> { pContext.response().putHeader(HttpHeaderNames.CONTENT_LENGTH.toString(), Integer.toString(t.length)); pContext.response().write(Buffer.buffer(t)); }); + return pContext.response(); } @@ -222,15 +231,16 @@ public Router getRouter(Router pRouter) { .asList(t) .stream() .forEach((service) -> { + getLog().debug(() -> "Adding OpenAPI service handle:" + service.getOperationId()); apiFactory.addHandlerByOperationId(service.getOperationId(), (routingContext) -> { - if (isSecurityEnable()) { + if (isSecurityEnable() && service.isSecure()) { if (routingContext.user() == null) { routingContext.fail(401); return; } - routingContext.user().isAuthorized(AUTHORIZATION_PREFIX + ":" + service.getOperationId(), (event) -> { + routingContext.user().isAuthorized(service.getAuthority(), (event) -> { boolean authSuccess = event.succeeded() ? event.result() : false; if (authSuccess) { process(routingContext, service.getServiceUniqueId()); @@ -247,8 +257,20 @@ public Router getRouter(Router pRouter) { apiFactory.addFailureHandlerByOperationId(service.getOperationId(), (routingContext) -> { routingContext .response() - .setStatusCode(400) - .end(routingContext.failure().toString()); + .setStatusCode(routingContext.statusCode()) + .end(generateErrorResponse(routingContext)); + }); + apiFactory.setValidationFailureHandler((routingContext) -> { + routingContext + .response() + .setStatusCode(routingContext.statusCode()) + .end(generateErrorResponse(routingContext)); + }); + apiFactory.setNotImplementedFailureHandler((routingContext) -> { + routingContext + .response() + .setStatusCode(routingContext.statusCode()) + .end(generateErrorResponse(routingContext)); }); }); }); @@ -256,6 +278,13 @@ public Router getRouter(Router pRouter) { return apiFactory.getRouter(); } + protected String generateErrorResponse(RoutingContext pContext) { + return Optional + .ofNullable(pContext.failure()) + .map(error -> ExceptionUtils.getMessage(error)) + .orElse(pContext.getBodyAsString()); + } + public boolean isSecurityEnable() { return mSecurityEnable; } diff --git a/src/main/java/in/erail/service/RESTService.java b/src/main/java/in/erail/service/RESTService.java index 429130f..bd6c57e 100644 --- a/src/main/java/in/erail/service/RESTService.java +++ b/src/main/java/in/erail/service/RESTService.java @@ -1,6 +1,5 @@ package in.erail.service; - import in.erail.model.RequestEvent; import in.erail.model.ResponseEvent; import io.reactivex.Maybe; @@ -10,7 +9,14 @@ * @author vinay */ public interface RESTService { + String getOperationId(); + String getServiceUniqueId(); + Maybe process(RequestEvent pRequest); + + String getAuthority(); + + boolean isSecure(); } diff --git a/src/main/java/in/erail/service/RESTServiceImpl.java b/src/main/java/in/erail/service/RESTServiceImpl.java index 2f29adf..b3150ab 100644 --- a/src/main/java/in/erail/service/RESTServiceImpl.java +++ b/src/main/java/in/erail/service/RESTServiceImpl.java @@ -1,5 +1,6 @@ package in.erail.service; +import com.google.common.net.MediaType; import io.reactivex.schedulers.Schedulers; import io.vertx.core.json.JsonObject; import io.vertx.reactivex.core.Vertx; @@ -7,6 +8,7 @@ import in.erail.glue.annotation.StartService; import in.erail.model.RequestEvent; import in.erail.model.ResponseEvent; +import io.netty.handler.codec.http.HttpResponseStatus; import io.reactivex.Scheduler; import io.reactivex.Single; import io.vertx.reactivex.core.eventbus.Message; @@ -18,12 +20,17 @@ */ public abstract class RESTServiceImpl implements RESTService { + private static final ResponseEvent DEFAULT_REPONSE_EVENT = new ResponseEvent(); + private String mOperationId; private String mServiceUniqueId; private Vertx mVertx; private boolean mEnable = false; private Logger mLog; private Scheduler mScheduler = Schedulers.io(); + private ResponseEvent mDefaultResponseEvent = DEFAULT_REPONSE_EVENT; + private boolean secure = false; + private String authority; @StartService public void start() { @@ -33,13 +40,12 @@ public void start() { .consumer(getServiceUniqueId()) .toFlowable() .subscribeOn(getScheduler()) + .flatMapSingle(this::handleRequest) .doOnSubscribe((s) -> getLog().info(() -> String.format("%s[%s] service started", getServiceUniqueId(), Thread.currentThread().getName()))) .doOnTerminate(() -> getLog().info(() -> String.format("%s[%s] service stopped", getServiceUniqueId(), Thread.currentThread().getName()))) - .flatMapSingle(this::handleRequest) - .subscribe( - resp -> getLog().trace(() -> resp.toString()), - err -> getLog().error(() -> String.format("Process exception:[%s],Error:[%s]", getServiceUniqueId(), ExceptionUtils.getStackTrace(err))) - ); + .doOnCancel(() -> getLog().info(() -> String.format("%s[%s] service stopped(cancel)", getServiceUniqueId(), Thread.currentThread().getName()))) + .doOnComplete(() -> getLog().info(() -> String.format("%s[%s] service stopped(complete)", getServiceUniqueId(), Thread.currentThread().getName()))) + .subscribe(resp -> getLog().trace(() -> resp.toString())); } } @@ -48,9 +54,18 @@ public Single handleRequest(Message pMessage) { .just(pMessage) .map(m -> pMessage.body().mapTo(RequestEvent.class)) .flatMapMaybe(req -> process(req)) - .toSingle(new ResponseEvent()) + .toSingle(getDefaultResponseEvent()) .map(resp -> JsonObject.mapFrom(resp)) - .doOnSuccess(resp -> pMessage.reply(resp)); + .doOnSuccess(resp -> pMessage.reply(resp)) + .doOnError(err -> { + ResponseEvent resp = new ResponseEvent() + .setStatusCode(HttpResponseStatus.BAD_REQUEST.code()) + .setMediaType(MediaType.PLAIN_TEXT_UTF_8) + .setBody(ExceptionUtils.getMessage(err).getBytes()); + pMessage.reply(JsonObject.mapFrom(resp)); + }) + .doOnError(oerr -> getLog().error(() -> String.format("Process exception:[%s],Error:[%s]", getServiceUniqueId(), ExceptionUtils.getStackTrace(oerr)))) + .onErrorReturnItem(new JsonObject()); } @Override @@ -103,4 +118,29 @@ public void setScheduler(Scheduler pScheduler) { this.mScheduler = pScheduler; } + public ResponseEvent getDefaultResponseEvent() { + return mDefaultResponseEvent; + } + + public void setDefaultResponseEvent(ResponseEvent pDefaultResponseEvent) { + this.mDefaultResponseEvent = pDefaultResponseEvent; + } + + @Override + public boolean isSecure() { + return secure; + } + + public void setSecure(boolean pSecure) { + this.secure = pSecure; + } + + @Override + public String getAuthority() { + return authority; + } + + public void setAuthority(String pAuthority) { + this.authority = pAuthority; + } } diff --git a/src/test/java/in/erail/route/CORSRouteBuilderTest.java b/src/test/java/in/erail/route/CORSRouteBuilderTest.java index 6b5ef16..cadba29 100644 --- a/src/test/java/in/erail/route/CORSRouteBuilderTest.java +++ b/src/test/java/in/erail/route/CORSRouteBuilderTest.java @@ -30,7 +30,7 @@ public void testProcess(TestContext context) { Async async = context.async(); Server server = Glue.instance().resolve("/in/erail/server/Server"); - + server .getVertx() .createHttpClient() @@ -38,9 +38,10 @@ public void testProcess(TestContext context) { .putHeader("content-type", "application/json") .putHeader(HttpHeaders.ORIGIN, "https://test.com") .putHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "POST") + .putHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, "cache-control,content-type,postman-token") .handler(response -> { context.assertEquals(response.statusCode(), 200, response.statusMessage()); - context.assertEquals(response.getHeader(HttpHeaderNames.ACCESS_CONTROL_ALLOW_METHODS.toString()), "GET,POST,OPTIONS"); + context.assertEquals(response.getHeader(HttpHeaderNames.ACCESS_CONTROL_ALLOW_METHODS.toString()), "DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT"); context.assertEquals(response.getHeader(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString()), "*"); context.assertEquals(response.getHeader(HttpHeaderNames.ACCESS_CONTROL_MAX_AGE.toString()), "3600"); context.assertEquals(response.getHeader(HttpHeaderNames.ACCESS_CONTROL_ALLOW_HEADERS.toString()), "X-POST"); diff --git a/src/test/java/in/erail/service/BinaryBodyService.java b/src/test/java/in/erail/service/BinaryBodyService.java index 63c86b3..dd8d0eb 100644 --- a/src/test/java/in/erail/service/BinaryBodyService.java +++ b/src/test/java/in/erail/service/BinaryBodyService.java @@ -1,7 +1,6 @@ package in.erail.service; import com.google.common.base.Strings; -import com.google.common.net.HttpHeaders; import com.google.common.net.MediaType; import in.erail.model.RequestEvent; @@ -28,7 +27,7 @@ public Maybe process(RequestEvent pRequest) { } ResponseEvent response = new ResponseEvent(); - response.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8); + response.setMediaType(MediaType.PLAIN_TEXT_UTF_8); JsonObject jsonBody = new JsonObject(Buffer.buffer(pRequest.getBody())); diff --git a/src/test/java/in/erail/service/BroadcastService.java b/src/test/java/in/erail/service/BroadcastService.java index fb8d21e..6413804 100644 --- a/src/test/java/in/erail/service/BroadcastService.java +++ b/src/test/java/in/erail/service/BroadcastService.java @@ -1,14 +1,14 @@ package in.erail.service; import com.google.common.base.Strings; -import com.google.common.net.HttpHeaders; import com.google.common.net.MediaType; -import in.erail.test.TestConstants; -import io.vertx.core.json.JsonObject; + import in.erail.model.RequestEvent; import in.erail.model.ResponseEvent; +import in.erail.test.TestConstants; import io.netty.handler.codec.http.HttpResponseStatus; import io.reactivex.Maybe; +import io.vertx.core.json.JsonObject; /** * @@ -35,7 +35,7 @@ public Maybe process(RequestEvent pRequest) { ResponseEvent response = new ResponseEvent(); response.setBody(TestConstants.Service.Message.successMessage().toString().getBytes()); - response.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8); + response.setMediaType(MediaType.JSON_UTF_8); return Maybe.just(response); } diff --git a/src/test/java/in/erail/test/TestConstants.java b/src/test/java/in/erail/test/TestConstants.java index 50b126f..4b3ce65 100644 --- a/src/test/java/in/erail/test/TestConstants.java +++ b/src/test/java/in/erail/test/TestConstants.java @@ -8,8 +8,13 @@ */ public class TestConstants { - public static final String ACCESS_TOKEN = "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI3UU0zSVNoWkstZWtwaXlfODRXR2ZweThRZFhHa3NfVDNBUjNwVDBfOHBrIn0.eyJqdGkiOiJlNTI2YTNiMC04MDIwLTRiYTktOGFmZi02YzBmYTZkYjhhNGUiLCJleHAiOjE1MTAwNzc2MjIsIm5iZiI6MCwiaWF0IjoxNTEwMDc3MzIyLCJpc3MiOiJodHRwczovL29wZW5pZC5lcmFpbC5pbi9hdXRoL3JlYWxtcy9BUElHYXRld2F5IiwiYXVkIjoidGVzdF9lcmFpbF9pbiIsInN1YiI6ImNhMjUwN2Y3LTc0N2QtNGY5Ny04YTFkLTI4NGZmODQ1YWVhNCIsInR5cCI6IkJlYXJlciIsImF6cCI6InRlc3RfZXJhaWxfaW4iLCJub25jZSI6Im56QTJNamRmZmYiLCJhdXRoX3RpbWUiOjE1MTAwNzcyNTIsInNlc3Npb25fc3RhdGUiOiIyYjExNjEzOC1hMDdiLTQ3MjQtYTkzZi02NzM0YzRjMWM0ODIiLCJhY3IiOiIwIiwiYWxsb3dlZC1vcmlnaW5zIjpbXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIkFQSV9WMV9UQVNLX1NFUlZJQ0UiLCJBUElfVjFfQlJPQURDQVNUX1NFUlZJQ0UiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInByZWZlcnJlZF91c2VybmFtZSI6ImFnZW50MSJ9.XrdyqCOaSNq2egPRXr8FdKHm3EqTnXTna37AK7JPeT_FDZSWDTsHvtW20hsW1lmq_7WoGFyt5SLFG_RTSA0GvfelArMDDwLhGIAM6UYEX3sNGvgHR0g3PQuiK-ACfYXdvrzWmJUANe0xxJBRa54Xpe7CkJg98qcDDP9-qvtmRgku6SGnFb9HBmkCiYs-D2G8Ems7TwDgxsFf4NVm2q5zPXmduJW4GFHCmBZK-8HwetmC4o8VORf0_lKhn-xF1Cw97qYkD4vzajQE9uW6hOiJYXZgWtp7D1lx79ts4_yMdppCdzMylv7lZppU6gezACdJwTyYQ1xBl9IZcEnv4qBEvg"; - + public static final String ACCESS_TOKEN = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJwZXJtaXNza" + + "W9ucyI6W10sImlhdCI6MTU0NjIxNzI2Mywic3ViIjoidGVzdHVzZXIifQ.LKd5wNfsmNWIGh6j5rl0xvr" + + "MdII7_doX6pF-qs0qvf7aIffbUpKoGAA36EQHU04D5WyikbciI7PseIw9YakV2yiIK798dD8Av4u4D5P2" + + "-1UGMa9dmD0jR_G15C2LsiSRLx-njJI_qmq5Iuu1ud4QKL67-tah40I_HcZWrAgywuZ143Fw0f5rf4wHs" + + "unx7Cm_c5UykvNjMZbxo_Ati6py3hsvydZq6f1CfMU0mPST9Lq4FwzdPe_sglt9F5rTB95oIYxVkPakzz" + + "nVcgDojkuGbFXcPTFLtwMxDXOD0tm8dwWYxKqokFRpQcl7ni0AiJfn1VeuCxG8QjCmtK_ti818pg"; + public static class Service { public static class Broadcast {