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.
Related
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!
I want to write REST service and I choose JWT for securing this rest service.
I declare 1 min for token, afterwards what I must do?
I must refresh token or something else?
If I must refresh token, user can call service's method with this token?
Token code
package com.example.demo.config;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.ArrayList;
import java.util.Arrays;
public class TokenAuthenticationService {
//field of conf
static final long EXPIRATIONTIME = 60_000; // 1 min
static final String SECRET = "msg";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";
//generate token
public static void addAuthentication(HttpServletResponse res, Authentication auth) {
String concattedRoles = "";
for (GrantedAuthority ga : auth.getAuthorities()) {
if (!"".equals(concattedRoles))
concattedRoles += "," + ga.getAuthority();
else
concattedRoles += ga.getAuthority();
}
String JWT = Jwts.builder().setSubject(auth.getName()).claim("roles", concattedRoles)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
.signWith(SignatureAlgorithm.HS512, SECRET).compact();
res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);
}
//get token from request header.
public static Authentication getAuthentication(HttpServletRequest request) {
try {
System.out.println("(Authentication getAuthentication(HttpServletRequest request)");
String token = request.getHeader(HEADER_STRING);
System.out.println("token=>"+token);
if (token != null) {
Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody();
String user = claims.getSubject();
String roles = (String) claims.get("roles");
if(claims.getExpiration().before(new Date(System.currentTimeMillis())))
throw new Exception(); //Here trow exception.
List<String> roleList = Arrays.asList(roles.split("\\s*,\\s*"));
List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
for (int i = 0; i < roleList.size(); i++) {
System.out.println(roleList.get(i));
SimpleGrantedAuthority abv = new SimpleGrantedAuthority(roleList.get(i));
grantedAuths.add(abv);
}
System.out.println(grantedAuths);
return user != null ? new UsernamePasswordAuthenticationToken(user, null, grantedAuths) : null;
}
return null;
}catch (Exception e){
System.out.println(e);
return null;
}
}
}
How we implemented is -
First time user logs in we send them a token and a refresh token.
Client side then uses the 'token' in the header to make further API calls.
At client side, we maintain e countdown of 15 minutes (which is lesser than the expiry time of the main token), after which from the client side we send a request to the server with both token and refresh token.
After getting a valid refresh token along with the main token, the server sends back a new token with increased exipiry time.
Hope this helps.
Basically refresh_token is used for giving back a valid access_token to the user upon request. And refresh_tokens are usually long-lived rather than short-lived.
Personally, my design for securing a RESTful API is just to let them request the access_token to my endpoint i.e https://api.example.com/oauth/token every time, I don't provide a refresh_token because the idea for me is just to let them in into the resource, nothing else. And usually, the requesting resource will not be staying for so long on a particular session. For the other concerns of the server getting too many requests on the same user/session, you can implement a rate-limiting to your servers or token endpoint.
I based my API security implementations on PayPal and JHipster. They do not provide refresh_tokens to their respective RESTful API implementations, because in the end, refresh_tokens are optional to be used, and it's just a matter of what you want to achieve upon securing your RESTful endpoints.
For more information about refresh_token you can these links:
When to use JWT Tokens and Understanding refresh tokens.
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
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.
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.