In a given moment in time an authenticated session is created.
I need to create a jersey client (post method) using that authenticated session.
I've tried set the JSESSIONID in the jersey client but it doesn't recognize the session.
Client client = Client.create();
final String url = "http://localhost:8080/api/send";
WebResource wr = client.resource(url);
javax.ws.rs.core.Cookie cookie=new javax.ws.rs.core.Cookie("JSESSIONID", "521448844J5WE54D");
wr.cookie(cookie);
// Set POST parameters
FormDataMultiPart multipart = new FormDataMultiPart();
FormDataBodyPart fdp = new FormDataBodyPart("file", uploadedInputStream, MediaType.MULTIPART_FORM_DATA_TYPE);
multipart.bodyPart(fdp);
String response = wr.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(String.class, multipart);
System.out.println(response);
I've tried also the code below, that in the jersey client I call first an API to authenticate the session and then try to use the same client object to call another API that require a auth session, didn't work.
Client client = Client.create();
final String url = "http://localhost:8080/api/auth";
WebResource wr = client.resource(url);
//set parametes for request
MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
queryParams.add("user", "admin");
queryParams.add("pass", "123456");
wr.queryParams(queryParams);
ClientResponse response = wr.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(ClientResponse.class);
System.out.println(response.getCookies().toString());
//------------------------------------------------------------
final String url2 = "http://localhost:8080/api/send";
WebResource wr2 = client.resource(url2);
// Set POST parameters
FormDataMultiPart multipart = new FormDataMultiPart();
FormDataBodyPart fdp = new FormDataBodyPart("file", uploadedInputStream, MediaType.MULTIPART_FORM_DATA_TYPE);
multipart.bodyPart(fdp);
String response2 = wr2.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(String.class, multipart);
System.out.println(response2);
How can I do that ? I mean, how to use an authenticated JSESSIONID in a new jersey client connection ?
Regards.
I think the best way to do is to use JWT for user Authorization.
I am assuming that you have already authenticated the user via an API Endpoint. Once the user is authenticated, you can reply back a header element. You can read more about JWT # https://jwt.io/introduction/
Your implementation should look like the following steps.
1) Authenticate the user and upon successful authentication, add "Authorization: " token to the response.
2) In every API call, expect the user to pass the Authorization header with each request and use a Filter to authorize the user by parsing the JWT Token. You may want to #Inject the Parser and make sure that your parser is Threadsafe.
3-a) If the JWT Token is valid, you let the request pass through to your resource.
3-b) If the JWT Token is invalid, you reply back wit HTTP 401.
Here is a sample implementation.
import com.google.inject.Inject;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.proc.BadJOSEException;
import com.nimbusds.jose.proc.SecurityContext;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.JWTParser;
import com.nimbusds.jwt.proc.ConfigurableJWTProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Priority;
import javax.ws.rs.Priorities;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.text.ParseException;
#PreMatching
#Priority(Priorities.AUTHENTICATION)
#Provider
#Secured
public class SimpleAuthorizationFilter implements ContainerRequestFilter {
static JWTParser jwtParser = null;
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleAuthorizationFilter.class);
#Inject
private ConfigurableJWTProcessor jwtProcessor;
public SimpleAuthorizationFilter() {
LOGGER.debug("Init {}", getClass().getName());
}
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Began authorization filter for {}", requestContext.getUriInfo().getPath());
}
MultivaluedMap < String, String > headers = requestContext.getHeaders();
JWT jwt = null;
if (headers.containsKey(AccessTokens.AUTHORIZATION)) {
String accessToken = headers.getFirst(AccessTokens.AUTHORIZATION);
try {
jwt = JWTParser.parse(accessToken);
} catch (ParseException parseException) {
LOGGER.error("Unable to parse JWT Token {}, reason {}", requestContext.getUriInfo().getPath(), parseException.getMessage());
throw new WebApplicationException("Unable to parse JWT Token", Response.Status.UNAUTHORIZED);
}
// Check if JWT has been init successfully.
if (jwt == null) {
LOGGER.error("JWT is null {}", requestContext.getUriInfo().getPath());
throw new WebApplicationException("Unable to init JWT", Response.Status.UNAUTHORIZED);
}
try {
if (jwt.getJWTClaimsSet().getExpirationTime().before(new java.util.Date())) {
LOGGER.debug("JWT Token expired on {}, requesting new token ", jwt.getJWTClaimsSet().getExpirationTime().toString());
} else {
// Do nothing, continue as usual.
}
} catch (ParseException e) {
LOGGER.error("Authorization failed # {} , due to {}", requestContext.getUriInfo().getPath(), e.getMessage());
throw new WebApplicationException("Unable to Authorize " + e.getMessage(), Response.Status.UNAUTHORIZED);
}
SecurityContext ctx = null; // optional context parameter, not required here
JWTClaimsSet claimsSet = null;
try {
claimsSet = jwtProcessor.process(accessToken, ctx);
} catch (ParseException e) {
LOGGER.error("Authorization failed # ParseException {} , due to {}", requestContext.getUriInfo().getPath(), e.getMessage());
throw new WebApplicationException("Unable to Authorize " + e.getMessage(), Response.Status.UNAUTHORIZED);
} catch (BadJOSEException e) {
LOGGER.error("Authorization failed # BadJOSEException {} , due to {}", requestContext.getUriInfo().getPath(), e.getMessage());
throw new WebApplicationException("Unable to Authorize " + e.getMessage(), Response.Status.UNAUTHORIZED);
} catch (JOSEException e) {
LOGGER.error("Authorization failed # JOSEException {} , due to {}", requestContext.getUriInfo().getPath(), e.getMessage());
throw new WebApplicationException("Unable to Authorize " + e.getMessage(), Response.Status.UNAUTHORIZED);
}
// This should not have happened.
if (claimsSet == null) {
LOGGER.error("JWT Claim is null failed # {} , due to {}", requestContext.getUriInfo().getPath());
throw new WebApplicationException("Unable to Authorize", Response.Status.UNAUTHORIZED);
}
} else {
LOGGER.error("Authorization header is missing {}", requestContext.getUriInfo().getPath());
throw new WebApplicationException("Authorization header is missing", Response.Status.UNAUTHORIZED);
}
}
}
I actually created an annotation #Secured and any resource method annotated with #Secured will be greeted first with this filter.
Here is my Annotation:
import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
#NameBinding
#Retention(RUNTIME)
#Target({TYPE, METHOD})
public #interface Secured { }
Then I created a DynamicFeature as:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;
#Provider
public class ResourceFilterBindingFeature implements DynamicFeature {
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceFilterBindingFeature.class);
#Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
if (resourceInfo.getResourceMethod().isAnnotationPresent(Secured.class)) {
LOGGER.info("{} is annotated to be a secure method " , resourceInfo.getResourceMethod().getName() );
context.register(CustomAuthorizationFilter.class);
}
}
}
You will need to register the above DyamicFeature in Jersey as
register(SimpleAuthorizationFilter.class)
Finally, here is my resource that I used to test
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
#Path("/authorizationTest")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public class AuthorizationTest {
#GET
#Path("/secure")
#Secured
public Response secure(){
return Response.ok(MediaType.APPLICATION_JSON).build();
}
#GET
#Path("/unsecure")
public Response unsecure(){
return Response.ok(MediaType.APPLICATION_JSON).build();
}
}
Hope that helps.
Related
I'm writing Unit test for the below Class Implementation that sends requests to an API the verifies desired Response.
So the Issue I'm facing is how to correctly mock the dependencies within the methods since the corresponding methods depend on the first method that gets an Authentication token.
Kindly assist with any pointers on how to do it correctly and avoid the timeout exception I'm getting.
The class under test
package com.darajaapi.daraja.transactions.services;
import com.darajaapi.daraja.transactions.config.MpesaConfiguration;
import com.darajaapi.daraja.transactions.dtos.*;
import com.darajaapi.daraja.transactions.exceptions.ResponseException;
import com.darajaapi.daraja.transactions.utils.HelperUtility;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.util.Objects;
import static com.darajaapi.daraja.transactions.utils.Constants.*;
#Service
#Slf4j
public class DarajaApiImpl implements DarajaApi {
private MpesaConfiguration mpesaConfiguration;
private OkHttpClient okHttpClient;
private ObjectMapper objectMapper;
public DarajaApiImpl(OkHttpClient okHttpClient, MpesaConfiguration mpesaConfiguration, ObjectMapper objectMapper){
this.okHttpClient = okHttpClient;
this.objectMapper = objectMapper;
this.mpesaConfiguration = mpesaConfiguration;
}
#Override
public AccessTokenResponse getAccessToken() throws ResponseException {
// get the Base64 rep of consumerKey + ":" + consumerSecret
String encodedCredentials = HelperUtility.toBase64String(String.format("%s:%s", mpesaConfiguration.getConsumerKey(),
mpesaConfiguration.getConsumerSecret()));
Request request = new Request.Builder()
.url(String.format("%s?grant_type=%s", mpesaConfiguration.getOauthEndpoint(), mpesaConfiguration.getGrantType()))
.get()
.addHeader(AUTHORIZATION_HEADER_STRING, String.format("%s %s", BASIC_AUTH_STRING, encodedCredentials))
.addHeader(CACHE_CONTROL_HEADER, CACHE_CONTROL_HEADER_VALUE)
.build();
try {
Response response = okHttpClient.newCall(request).execute();
var responseBody = response.body();
var responseString = responseBody != null ? responseBody.string() : null;
if(!StringUtils.hasLength(responseString)){
log.warn("Empty response from Daraja api");
throw new ResponseException("Empty response from Daraja api");
}
// using Jackson to Decode the ResponseBody ...
return objectMapper.readValue(responseString, AccessTokenResponse.class);
} catch (IOException | ResponseException e) {
log.error(String.format("Could not get access token. -> %s", e.getLocalizedMessage()));
throw new ResponseException(e.getLocalizedMessage());
}
}
#Override
public RegisterUrlResponse registerUrl() throws ResponseException {
AccessTokenResponse accessToken = getAccessToken();
RegisterUrlRequest registerUrlRequest = new RegisterUrlRequest();
registerUrlRequest.setShortCode(mpesaConfiguration.getShortcode());
registerUrlRequest.setResponseType(mpesaConfiguration.getResponseType());
registerUrlRequest.setConfirmationURL(mpesaConfiguration.getConfirmationUrl());
registerUrlRequest.setValidationURL(mpesaConfiguration.getValidationUrl());
RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, Objects.requireNonNull(HelperUtility.toJson(registerUrlRequest)));
Request request = new Request.Builder()
.url(mpesaConfiguration.getRegisterUrl())
.post(body)
.addHeader(AUTHORIZATION_HEADER_STRING, String.format("%s %s", BEARER_AUTH_STRING, accessToken.getAccessToken()))
.build();
try {
Response response = okHttpClient.newCall(request).execute();
var responseBody = response.body();
var responseString = responseBody != null ? responseBody.string() : null;
if(!StringUtils.hasLength(responseString)){
log.warn("Empty response from Daraja api");
throw new ResponseException("Empty response from Daraja api");
}
// using Jackson to Decode the ResponseBody ...
return objectMapper.readValue(responseString, RegisterUrlResponse.class);
} catch (IOException e) {
log.error(String.format("Could not register url =>%s", e.getLocalizedMessage()));
return null;
}
}
#Override
public C2bTransactionResponse simulateC2bTransaction(C2bTransactionRequest c2bTransactionRequest) throws ResponseException {
AccessTokenResponse accessTokenResponse = getAccessToken();
RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, Objects.requireNonNull(HelperUtility.toJson(c2bTransactionRequest)));
Request request = new Request.Builder()
.url(mpesaConfiguration.getSimulateC2bTransactionUrl())
.post(body)
.addHeader(AUTHORIZATION_HEADER_STRING, String.format("%s %s", BEARER_AUTH_STRING, accessTokenResponse.getAccessToken()))
.build();
try {
Response response = okHttpClient.newCall(request).execute();
assert response.body() != null;
return objectMapper.readValue(response.body().string(), C2bTransactionResponse.class);
} catch (IOException e) {
log.error(String.format("Could not simulate C2B transaction =>%s", e.getLocalizedMessage()));
return null;
}
}
}
The Tests for the first two methods...
package com.darajaapi.daraja.transactions.services;
import com.darajaapi.daraja.transactions.config.MpesaConfiguration;
import com.darajaapi.daraja.transactions.dtos.AccessTokenResponse;
import com.darajaapi.daraja.transactions.dtos.RegisterUrlResponse;
import com.darajaapi.daraja.transactions.exceptions.ResponseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.OkHttpClient;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.io.IOException;
import java.net.URL;
import java.util.Objects;
#DisplayName("Writing Tests for Daraja Api Impl / service")
#ExtendWith(MockitoExtension.class)
public class DarajaApiImplTest {
private static final String CUSTOMER_KEY = "GPGd8hIoa26OSAOffCzSomeKeyZjGJrfKg9";
private static final String CUSTOMER_SECRET = "fAzSomeSecret3patXe";
private static final String GRANT_TYPE = "client_credentials";
private MockWebServer mockWebServer;
private DarajaApiImpl darajaApiImpl;
#Mock
private MpesaConfiguration mpesaConfiguration;
#Mock
private ObjectMapper objectMapper;
#Mock
private AccessTokenResponse accessTokenResponse;
#Mock
private RegisterUrlResponse registerUrlResponse;
#BeforeEach
void setUp() throws IOException {
mockWebServer = new MockWebServer();
mockWebServer.start();
MockitoAnnotations.openMocks(this);
URL mockServerBaseUrl = mockWebServer.url("").url();
URL tokenUrl = new URL(mockServerBaseUrl, "/token");
when(mpesaConfiguration.getConsumerKey()).thenReturn(CUSTOMER_KEY);
when(mpesaConfiguration.getConsumerSecret()).thenReturn(CUSTOMER_SECRET);
when(mpesaConfiguration.getOauthEndpoint()).thenReturn(String.valueOf(tokenUrl));
when(mpesaConfiguration.getGrantType()).thenReturn(GRANT_TYPE);
accessTokenResponse.setAccessToken("0W0uNniSomeTokengQpO2x23DaG");
accessTokenResponse.setExpiresIn("3599");
darajaApiImpl = new DarajaApiImpl(new OkHttpClient(), mpesaConfiguration, objectMapper);
}
#AfterEach
void tearDown() throws IOException {
mockWebServer.shutdown();
}
#Test
void getAccessTokenMethod_Returns_Token_Test() throws JsonProcessingException, InterruptedException, ResponseException {
final String responseBody = "{\"access_token\":\"0W0uNniCevTmRFV8LgQpO2x\", \"expires_in\":\"3599\"}";
when(objectMapper.readValue(responseBody, AccessTokenResponse.class)).thenReturn(accessTokenResponse);
mockWebServer.enqueue(new MockResponse()
.setBody(responseBody)
.addHeader("Content-Type", "application/json"));
AccessTokenResponse response = darajaApiImpl.getAccessToken();
RecordedRequest recordedRequest = mockWebServer.takeRequest();
System.out.println(response);
assertNotNull(response);
assertEquals("GET", recordedRequest.getMethod());
assertEquals(response.getAccessToken(), accessTokenResponse.getAccessToken());
}
#Test
void getAccessTokenMethod_Throws_Error_When_Response_IsEmpty() {
mockWebServer.enqueue(new MockResponse()
.setBody("")
.addHeader("Content-Type", "application/json"));
final ResponseException thrown = assertThrows(
ResponseException.class,
() -> darajaApiImpl.getAccessToken()
);
assertEquals("Empty response from Daraja api", thrown.getMessage());
}
#Test
void registerUrlMethod_Returns_Success() throws InterruptedException, ResponseException, JsonProcessingException {
final String responseBody = "{\"access_token\":\"0W0uNniCevTmRFV8LgQpO2x\", \"expires_in\":\"3599\"}";
registerUrlResponse.setResponseCode("0");
registerUrlResponse.setResponseDescription("someString");
registerUrlResponse.setOriginatorCoversationID("someId");
URL registerUrl = mockWebServer.url("/register").url();
when(mpesaConfiguration.getRegisterUrl()).thenReturn(String.valueOf(registerUrl));
when(darajaApiImpl.getAccessToken()).thenReturn(accessTokenResponse);
mockWebServer.enqueue(new MockResponse()
.setBody(String.valueOf(registerUrlResponse))
.addHeader("Content-Type", "application/json"));
RegisterUrlResponse response = darajaApiImpl.registerUrl();
RecordedRequest recordedRequest = mockWebServer.takeRequest();
System.out.println(response);
assertNotNull(response);
assertEquals("POST", recordedRequest.getMethod());
assertEquals(response.getResponseCode(), registerUrlResponse.getResponseCode());
}
}
This is the error I'm getting with the above implementation.
Any pointers will Help.
The first two tests are passing, the issue arises when testing the second method which depends on the first one.
I am using some external API to GET and POST some ressources, locally my code works fine with the call of different endPoints (GET, POST...) and even with Postman, but when i try to run my code in another platerform (where the ressources are), i get the 412 HTTP error due to a POST call : after looking on the internet, i found out that i should generate an ETagd of the entity (that i went to modify) and add it into the header of my POST endPoint.
For that, i used ShallowEtagHeaderFilter and the #Bean annotation(above the filter method) and the #SpringBootApplication annotation above my class, here is my code :
package main.Runners;
import io.testproject.java.annotations.v2.Parameter;
import okhttp3.*;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.configurationprocessor.json.JSONArray;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.context.annotation.Bean;
import org.springframework.web.filter.ShallowEtagHeaderFilter;
import javax.servlet.Filter;
#SpringBootApplication
public class ActionRunner {
#Parameter(description = "the project ID")
public static String projectId = "xxx";
#Parameter(description = "the test ID")
public static String testId = "yyy";
public static void main(String[] args) throws Exception {
try {
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
Request request = new Request.Builder()
.url("https://api.testproject.io/v2/projects/"+projectId+"/tests/"+testId)
.method("GET", null)
.addHeader("Authorization", "nzmo4DI08ykizYgcp9-5cCTArlxq7k7zt9MYhGmTcRk1")
.build();
Response response = client.newCall(request).execute();
System.out.println("================ this is our response headers ::: \n"+ response.headers());
} catch(Exception e) {
System.out.println(e);
}
}
#Bean
public ShallowEtagHeaderFilter shallowEtagHeaderFilter(){
return new ShallowEtagHeaderFilter();
}
}
I really need Your help since i cant generate any ETag parameter on my GET response header(after checking reponse.headers() ).
Thanks in advance!
From this artcle, I have implemented calling another rest API from my REST API method in micronaut gradle application. Since my REST API expects jwt token I am sending the same token I received with in current request. I am seeing Unauthorized error even token is being passed. Can anyone help in this regard. Below is my code.
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpStatus;
import io.appter.clientmgmt.models.ClientContact;
import io.appter.clientmgmt.repositories.IClientContactRepository;
import io.micronaut.http.uri.UriTemplate;
import io.micronaut.security.annotation.Secured;
import io.micronaut.security.authentication.Authentication;
import io.micronaut.security.rules.SecurityRule;
import io.micronaut.http.annotation.*;
import io.micronaut.http.client.RxHttpClient;
import io.micronaut.http.client.annotation.Client;
import io.reactivex.Flowable;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import javax.validation.constraints.NotNull;
import java.security.Security;
import java.util.List;
#Controller("/clientcontact")
//#Secured(SecurityRule.IS_ANONYMOUS)
public class ClientContactController {
private static final Logger LOG = LoggerFactory.getLogger(ClientContactController.class);
private IClientContactRepository clientContactRepository;
private final RxHttpClient httpClient;
public ClientContactController(IClientContactRepository clientContactRepository,
#Client("http://appterauthsvc-env.g2yapp2kcp.us-east-1.elasticbeanstalk.com") RxHttpClient httpClient) {
this.clientContactRepository = clientContactRepository;
this.httpClient = httpClient;
}
#Get("/")
public HttpStatus index() {
return HttpStatus.OK;
}
#Post("/")
#Secured(SecurityRule.IS_AUTHENTICATED)
public ClientContact createClientContact(#Body ClientContact clientContact,
Authentication authentication,
#Header("Authorization") String authorization) {
try {
List<ClientContact> existingClientContacts = clientContactRepository.getClientContactByClientId(clientContact.getClientId());
LOG.info("current contacts count for the client " + clientContact.getClientId() + " is " + existingClientContacts.size());
if (existingClientContacts.isEmpty()) {
User userObj = new User();
Long clientId = new Long(clientContact.getClientId());
userObj.setClientId(clientId);
userObj.setFirstName(clientContact.getFirstName());
userObj.setLastName(clientContact.getLastName());
userObj.setEmailId(clientContact.getEmailAddress());
userObj.setPhoneNo(clientContact.getContactNumber());
userObj.setIsActive(true);
LOG.info("User Email set is: "+userObj.getEmailId());
LOG.info("authorization token is: "+authorization);
HttpRequest<?> request = HttpRequest.POST("/user", userObj).bearerAuth(authorization);
String response = httpClient.toBlocking().retrieve(request);
LOG.info("Request Object: "+ request.toString());
LOG.info("Response Object: "+ response.toString());
LOG.info("User API executed.. ");
}
return clientContactRepository.createClientContact(clientContact);
} catch (Exception ex) {
LOG.error(ex.getMessage(), ex);
return null;
}
}
}
Thanks in advance.
Likely because #Header("Authorization") String authorization is returning something like Bearer xyz... and the bearerAuth method is adding Bearer to the string so you are sending Bearer Bearer xyz...
So just do .header(HttpHeaders.AUTHORIZATION, authorization)
Also as a side note you really shouldn't be doing blocking HTTP calls in this method. It's not the end of the world since in this case you're blocking an IO thread, however this type of code should be avoided.
I wasn't able to find out proper format how to send Response back to .JSP page after POST. First, how to obtain Response from Web service to Client?
Second question is how to call Client from Servlet.
Because second part is quite straightforward (create class instance in servlet in the proper doGet, doPost method), I will focus on the first question.
Snippet on the server side:
import java.math.BigInteger;
import java.util.List;
import java.util.logging.Logger;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.hibernate.SessionFactory;
// internal beans and classes
import com.deepam.util.BasicUtils;
import entities.CustomerRest;
import entities.DualInteger;
import entities.Dualloc;
import model.CustomerModel;
import model.DualModel;
import model.HibernateUtil;
#Path("/customer")
public class CustomerRestWS {
private final static Logger LOGGER = Logger.getLogger(CustomerRestWS.class.getName());
private CustomerModel cm = new CustomerModel();
private DualModel dm = new DualModel();
private final String CUSTSEQ = "customer_rest_seq";
SessionFactory sessionFactory;
/** Constructor
*/
public CustomerRestWS() {
super();
LOGGER.info("***" + LOGGER.getName());
sessionFactory = HibernateUtil.getSessionFactory();
}
...
#GET
#Path("/findcustseq")
#Produces(MediaType.APPLICATION_XML)
public DualInteger selectCustSeq() {
return cm.selectCustSeqNative(CUSTSEQ);
}
// post method how to save customer into DB
#POST
#Path("/create")
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_JSON) // JSON is used for clearity between Consumes/Produces on the Client side
public Response create(final CustomerRest cust) throws JSONException {
Response response;
LOGGER.info("***" + LOGGER.getName() + " Insert Customer, id, name, last name: " + cust.getId() + ", " + cust.getFirstName() + ", " + cust.getLastName());
try {
cm.create(cust);
}
catch (Exception ex) {
// internal error
LOGGER.info("***" + LOGGER.getName() + " Exception: " + ex.getMessage());
response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(Response.Status.INTERNAL_SERVER_ERROR.toString()).build();
return response;
}
// created
response = Response.status(Response.Status.CREATED)
.entity(Response.Status.CREATED.toString()).build();
return response;
}
...
On the Client side:
import java.text.MessageFormat;
import java.util.logging.Logger;
import javax.ws.rs.core.MediaType;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.DefaultClientConfig;
// internal beans
import entities.Customer;
import entities.DualInteger;
import entities.ListCustomers;
public class CustomerRestfulClient {
private final static Logger LOGGER = Logger.getLogger(CustomerRestfulClient.class.getName());
private WebResource webresource;
private Client client;
private static final String BASE_URI = "http://localhost:8080/RestfulOracleServer/rest/";
public CustomerRestfulClient() {
// init client
client = Client.create(new DefaultClientConfig());
// init webresource
webresource = client.resource(BASE_URI).path("customer");
}
...
/** method getCustIdXML for obtaining unique ID (from sequence) */
public DualInteger getCustIdXML() throws UniformInterfaceException {
WebResource resource = webresource.path(MessageFormat.format("findcustseq", new Object[] {}));
return resource.accept(MediaType.APPLICATION_XML).get(DualInteger.class);
}
/** method saveCustXML call other method to obtain unique ID, than save Bean to DB */
public ClientResponse saveCustXML(String firstName, String lastName) throws UniformInterfaceException {
DualInteger custId = getCustIdXML();
LOGGER.info("Seqence number: " + (custId.getSeq()));
Customer cust = new Customer(custId.getSeq(), firstName, lastName);
ClientResponse response = webresource.path("create").
accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_XML).post(ClientResponse.class, cust);
LOGGER.info("Entity: " + response.getStatus());
return response;
}
Notice classes Response on the Server side and ClientResponse on the Client Side. Look how are treated #Consumes, #Produces annotations on server side to and accept, type methods on the Client side. There were my sources of errors.
In servlet Controller for .jsp simply create Client for WS e.g. custClient = new CustomerRestfulClient(); in constructor and use the obvious methods doGet, doPost as obvious. The Servlet has its own Request, Response different from Request, Response of WS. Be carefully in MVC model, Controller is treated by server as Singleton. In concurrent environment you must keep session continuity. (The most simple way is to use local variables in methods, when it is indicated.) Links to similar topics:
Is it ok by REST to return content after POST?
RESTful Java Client with POST method
Environment: WildFly 8.1.
I deploy 2 applications on one server. One is connecting with other and trying to run POST method on rest service.
In service project I added:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("/rest")
public class RsActivator extends Application {
}
As far as I understand the user's guide for wildfly and jax-rs, this should be enough to run service listed below:
import javax.annotation.security.PermitAll;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import pl.patom.en.rest.model.LoginData;
import pl.patom.en.security.model.User;
import pl.patom.en.services.UserService;
#Path("services")
public class RestService {
#Inject
private UserService userService;
#PermitAll
#POST
#Consumes(MediaType.APPLICATION_JSON + ";charset=UTF-8")
#Path("/login")
public Response login(LoginData ld) {
User checkedUser = userService.findByLogin(ld.getUsername());
if (checkedUser == null || !checkedUser.getPassword().equals(ld.getPassword())) {
return Response.serverError().build();
}
return Response.ok().build();
}
}
In project where I call service I have this method:
public String login() {
try {
HttpClient client = HttpClientBuilder.create().build();
HttpPost postRequest = new HttpPost("http://localhost:8080/en/rest/services/login/");
LoginData ld = new LoginData(username, password);
Gson gson = new Gson();
String json = gson.toJson(ld);
StringEntity input = new StringEntity(json);
input.setContentType("application/json");
postRequest.setEntity(input);
postRequest.setHeader("Authorization", "Basic cm9vdDpyb290");
HttpResponse response = client.execute(postRequest);
if (response.getStatusLine().getStatusCode() == 200) {
loggedIn = true;
return "/secured/index.xhtml?faces-redirect=true";
} else {
loggedIn = false;
}
} catch (Exception e) {
loggedIn = false;
}
return null;
}
Why do I always get 200 OK response? It doesn't matter if I use #GET or #POST annotation = always OK. Secondly, ther is no debugger activity in method (application never stops on any breakpoint within this method):
public Response login(LoginData ld)
(It works when I use RESTClient in Firefox).
Oo, and there is another curious thing... In return with this 200 OK status I always get jsf login form.
Problem solved by adding: /rest/* to non-secured section of web-resource-collection.