I am trying to verify a jwt token and getting the exception: Exception in thread "main" java.lang.IllegalArgumentException: Only private key data is currently supported
Any pointers on how to verify a jwt token with public key?
import org.springframework.security.jwt.JwtHelper;
public boolean verify(String jwtToken) {
ResponseEntity<JwtKey> response = restTemplate.getForEntity(tokenKey, JwtKey.class);
JwtKey jwtKey = response.getBody();
Jwt decode = JwtHelper.decode(jwtToken);
System.out.println(decode);
System.out.println(decode.getClaims());
JwtHelper.decodeAndVerify(jwtToken, new RsaVerifier(jwtKey.getValue()));
return true;
}
Finally, I went with the below solution.
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.apache.commons.lang.StringUtils;
public boolean verify(String jwtToken) {
JWTKey jwtKey = restTemplateManager.getTokenPublicKey();
try {
JwtHelper.decodeAndVerify(jwtToken, new RsaVerifier(getRSAPublicKey(jwtKey.getValue())));
} catch (Exception e) {
logger.error("Error in verifying token{}", e);
return false;
}
return true;
}
private RSAPublicKey getRSAPublicKey(String publicKey) {
if( StringUtils.isBlank(publicKey)) return null;
publicKey = sanitaize(publicKey);
try {
KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(java.util.Base64.getDecoder().decode(publicKey));
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
logger.error("Error forming RSA key {}", e);
throw new GatewayException(e);
}
}
Create a RsaVerifier with public key:
#Bean RsaVerifier rsaVerifier(){
Resource resource = new ClassPathResource(pubKeyFilename);
try {
String pubKey = IOUtils.toString(resource.getInputStream(), "UTF-8");
return new RsaVerifier(pubKey);
} catch (final IOException e) {
throw new Exception("Cannot get public key to check JWT",e);
}
}
Use it when you want to decode:
Jwt jwt = JwtHelper.decodeAndVerify(token, rsaVerifier());
Related
I exposed Rest APIs, and I generated client code using Swagger 2 Java language with Feign library. The code gen generated the below OAuth RequestInterceptor. I am getting the below error when I use the oAuth as auth.
Error
feign.RetryableException: url values must be not be absolute.
at com.sam.feign.auth.OAuth.updateAccessToken(OAuth.java:95)
at com.sam.feign.auth.OAuth.apply(OAuth.java:83)
at feign.SynchronousMethodHandler.targetRequest(SynchronousMethodHandler.java:161)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:110)
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89)
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100)
at com.sun.proxy.$Proxy9.getUser(Unknown Source)
at com.sam.feign.clients.UserApiTest.getUserTest(UserApiTest.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: java.lang.IllegalArgumentException: url values must be not be absolute.
at feign.RequestTemplate.uri(RequestTemplate.java:434)
at feign.RequestTemplate.uri(RequestTemplate.java:421)
at feign.RequestTemplate.append(RequestTemplate.java:388)
at com.sam.feign.auth.OAuth$OAuthFeignClient.execute(OAuth.java:163)
at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:65)
at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:55)
at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:71)
at com.sam.feign.auth.OAuth.updateAccessToken(OAuth.java:93)
... 34 more
Swagger Generated oAuth supporting file
public class OAuth implements RequestInterceptor {
static final int MILLIS_PER_SECOND = 1000;
public interface AccessTokenListener {
void notify(BasicOAuthToken token);
}
private volatile String accessToken;
private Long expirationTimeMillis;
private OAuthClient oauthClient;
private TokenRequestBuilder tokenRequestBuilder;
private AuthenticationRequestBuilder authenticationRequestBuilder;
private AccessTokenListener accessTokenListener;
public OAuth(Client client, TokenRequestBuilder requestBuilder) {
this.oauthClient = new OAuthClient(new OAuthFeignClient(client));
this.tokenRequestBuilder = requestBuilder;
}
public OAuth(Client client, OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) {
this(client, OAuthClientRequest.tokenLocation(tokenUrl).setScope(scopes));
switch(flow) {
case accessCode:
case implicit:
tokenRequestBuilder.setGrantType(GrantType.AUTHORIZATION_CODE);
break;
case password:
tokenRequestBuilder.setGrantType(GrantType.PASSWORD);
break;
case application:
tokenRequestBuilder.setGrantType(GrantType.CLIENT_CREDENTIALS);
break;
default:
break;
}
authenticationRequestBuilder = OAuthClientRequest.authorizationLocation(authorizationUrl);
}
public OAuth(OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) {
this(new Client.Default(null, null), flow, authorizationUrl, tokenUrl, scopes);
}
#Override
public void apply(RequestTemplate template) {
// If the request already have an authorization (eg. Basic auth), do nothing
if (template.headers().containsKey("Authorization")) {
return;
}
// If first time, get the token
if (expirationTimeMillis == null || System.currentTimeMillis() >= expirationTimeMillis) {
updateAccessToken(template);
}
if (getAccessToken() != null) {
template.header("Authorization", "Bearer " + getAccessToken());
}
}
public synchronized void updateAccessToken(RequestTemplate template) {
OAuthJSONAccessTokenResponse accessTokenResponse;
try {
accessTokenResponse = oauthClient.accessToken(tokenRequestBuilder.buildBodyMessage());
} catch (Exception e) {
throw new RetryableException(400, e.getMessage(), template.request().httpMethod(), e, null, template.request());
}
if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) {
setAccessToken(accessTokenResponse.getAccessToken(), accessTokenResponse.getExpiresIn());
if (accessTokenListener != null) {
accessTokenListener.notify((BasicOAuthToken) accessTokenResponse.getOAuthToken());
}
}
}
public synchronized void registerAccessTokenListener(AccessTokenListener accessTokenListener) {
this.accessTokenListener = accessTokenListener;
}
public synchronized String getAccessToken() {
return accessToken;
}
public synchronized void setAccessToken(String accessToken, Long expiresIn) {
this.accessToken = accessToken;
this.expirationTimeMillis = System.currentTimeMillis() + expiresIn * MILLIS_PER_SECOND;
}
public TokenRequestBuilder getTokenRequestBuilder() {
return tokenRequestBuilder;
}
public void setTokenRequestBuilder(TokenRequestBuilder tokenRequestBuilder) {
this.tokenRequestBuilder = tokenRequestBuilder;
}
public AuthenticationRequestBuilder getAuthenticationRequestBuilder() {
return authenticationRequestBuilder;
}
public void setAuthenticationRequestBuilder(AuthenticationRequestBuilder authenticationRequestBuilder) {
this.authenticationRequestBuilder = authenticationRequestBuilder;
}
public OAuthClient getOauthClient() {
return oauthClient;
}
public void setOauthClient(OAuthClient oauthClient) {
this.oauthClient = oauthClient;
}
public void setOauthClient(Client client) {
this.oauthClient = new OAuthClient( new OAuthFeignClient(client));
}
public static class OAuthFeignClient implements HttpClient {
private Client client;
public OAuthFeignClient() {
this.client = new Client.Default(null, null);
}
public OAuthFeignClient(Client client) {
this.client = client;
}
public <T extends OAuthClientResponse> T execute(OAuthClientRequest request, Map<String, String> headers,
String requestMethod, Class<T> responseClass)
throws OAuthSystemException, OAuthProblemException {
RequestTemplate req = new RequestTemplate()
.append(request.getLocationUri())
.method(requestMethod)
.body(request.getBody());
for (Entry<String, String> entry : headers.entrySet()) {
req.header(entry.getKey(), entry.getValue());
}
Response feignResponse;
String body = "";
try {
feignResponse = client.execute(req.request(), new Options());
body = Util.toString(feignResponse.body().asReader());
} catch (IOException e) {
throw new OAuthSystemException(e);
}
String contentType = null;
Collection<String> contentTypeHeader = feignResponse.headers().get("Content-Type");
if(contentTypeHeader != null) {
contentType = StringUtil.join(contentTypeHeader.toArray(new String[0]), ";");
}
return OAuthClientResponseFactory.createCustomResponse(
body,
contentType,
feignResponse.status(),
responseClass
);
}
public void shutdown() {
// Nothing to do here
}
}
}
ApiClient.java have the below absolute URL which configured in swagger spec
public ApiClient() {
objectMapper = createObjectMapper();
apiAuthorizations = new LinkedHashMap<String, RequestInterceptor>();
feignBuilder = Feign.builder()
.encoder(new FormEncoder(new JacksonEncoder(objectMapper)))
.decoder(new JacksonDecoder(objectMapper))
.logger(new Slf4jLogger());
}
public ApiClient(String[] authNames) {
this();
for(String authName : authNames) {
RequestInterceptor auth = null;
if ("client-credentils-oauth2".equals(authName)) {
auth = new OAuth(OAuthFlow.application, "", "http://localhost:8080/app/oauth/token", "user.create");
} else if ("password-oauth2".equals(authName)) {
auth = new OAuth(OAuthFlow.password, "", "http://localhost:8080/app/oauth/token", "openid");
} else {
throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names");
}
addAuthorization(authName, auth);
}
}
Used the below dependencies
swagger-codegen-maven-plugin v2.4.28
feign-version 11.6
feign-form-version 3.8.0
oltu-version 1.0.1
Java 8
I am invoking the client by using below code
UserApi api = new ApiClient("client-credentils-oauth2","admin", "admin", null, null).buildClient(UserApi.class);
api.getUser(login, tenant)
I made the few changes in the generated oAuth.java file to make it work. Expecting the client generated code should work without making any manual changes.
public <T extends OAuthClientResponse> T execute(OAuthClientRequest request, Map<String, String> headers,
String requestMethod, Class<T> responseClass)
throws OAuthSystemException, OAuthProblemException {
// Added the below 3 lines
URI targetUri = URI.create(uri);
String target = targetUri.getScheme() + "://" + targetUri.getAuthority() ;
String path = targetUri.getPath();
RequestTemplate req = new RequestTemplate()
.uri(path)
.method(requestMethod)
.body(request.getBody())
.target(target); // Added this line
for (Entry<String, String> entry : headers.entrySet()) {
req.header(entry.getKey(), entry.getValue());
}
req = req.resolve(new HashMap<String, Object>()); // Added this line
Response feignResponse;
String body = "";
try {
feignResponse = client.execute(req.request(), new Options());
body = Util.toString(feignResponse.body().asReader());
} catch (IOException e) {
throw new OAuthSystemException(e);
}
String contentType = null;
Collection<String> contentTypeHeader = feignResponse.headers().get("Content-Type");
if(contentTypeHeader != null) {
contentType = StringUtil.join(contentTypeHeader.toArray(new String[0]), ";");
}
return OAuthClientResponseFactory.createCustomResponse(
body,
contentType,
feignResponse.status(),
responseClass
);
}
Appreciate if someone can assist me with this issue
I use a ErrorDecoder to return the right exception rather than a 500 status code.
Is there a way to retrieve the original message inside the decoder. I can see that it is inside the FeignException, but not in the decode method. All I have is the 'status code' and a empty 'reason'.
public class CustomErrorDecoder implements ErrorDecoder {
private final ErrorDecoder errorDecoder = new Default();
#Override
public Exception decode(String s, Response response) {
switch (response.status()) {
case 404:
return new FileNotFoundException("File no found");
case 403:
return new ForbiddenAccessException("Forbidden access");
}
return errorDecoder.decode(s, response);
}
}
Here the original message : "message":"Access to the file forbidden"
feign.FeignException: status 403 reading ProxyMicroserviceFiles#getUserRoot(); content:
{"timestamp":"2018-11-28T17:34:05.235+0000","status":403,"error":"Forbidden","message":"Access to the file forbidden","path":"/root"}
Also I use my FeignClient interface like a RestController so I don't use any other Controler populated with the proxy that could encapsulate the methods calls.
#RestController
#FeignClient(name = "zuul-server")
#RibbonClient(name = "microservice-files")
public interface ProxyMicroserviceFiles {
#GetMapping(value = "microservice-files/root")
Object getUserRoot();
#GetMapping(value = "microservice-files/file/{id}")
Object getFileById(#PathVariable("id") int id);
}
Here is a solution, the message is actually in the response body as a stream.
package com.clientui.exceptions;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.CharStreams;
import feign.Response;
import feign.codec.ErrorDecoder;
import lombok.*;
import java.io.*;
public class CustomErrorDecoder implements ErrorDecoder {
private final ErrorDecoder errorDecoder = new Default();
#Override
public Exception decode(String s, Response response) {
String message = null;
Reader reader = null;
try {
reader = response.body().asReader();
//Easy way to read the stream and get a String object
String result = CharStreams.toString(reader);
//use a Jackson ObjectMapper to convert the Json String into a
//Pojo
ObjectMapper mapper = new ObjectMapper();
//just in case you missed an attribute in the Pojo
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//init the Pojo
ExceptionMessage exceptionMessage = mapper.readValue(result,
ExceptionMessage.class);
message = exceptionMessage.message;
} catch (IOException e) {
e.printStackTrace();
}finally {
//It is the responsibility of the caller to close the stream.
try {
if (reader != null)
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
switch (response.status()) {
case 404:
return new FileNotFoundException(message == null ? "File no found" :
message);
case 403:
return new ForbiddenAccessException(message == null ? "Forbidden
access" : message);
}
return errorDecoder.decode(s, response);
}
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
public static class ExceptionMessage{
private String timestamp;
private int status;
private String error;
private String message;
private String path;
}
}
If you want to get the response payload body, with the Feign exception, just use this method:
feignException.contentUTF8();
Example:
try {
itemResponse = call(); //method with the feign call
} catch (FeignException e) {
logger.error("ResponseBody: " + e.contentUTF8());
}
It is suggested to use input stream instead of reader and map it to your object.
package com.clientui.exceptions;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.CharStreams;
import feign.Response;
import feign.codec.ErrorDecoder;
import lombok.*;
import java.io.*;
public class CustomErrorDecoder implements ErrorDecoder {
private final ErrorDecoder errorDecoder = new Default();
#Override
public Exception decode(String s, Response response) {
String message = null;
InputStream responseBodyIs = null;
try {
responseBodyIs = response.body().asInputStream();
ObjectMapper mapper = new ObjectMapper();
ExceptionMessage exceptionMessage = mapper.readValue(responseBodyIs, ExceptionMessage.class);
message = exceptionMessage.message;
} catch (IOException e) {
e.printStackTrace();
// you could also return an exception
return new errorMessageFormatException(e.getMessage());
}finally {
//It is the responsibility of the caller to close the stream.
try {
if (responseBodyIs != null)
responseBodyIs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
switch (response.status()) {
case 404:
return new FileNotFoundException(message == null ? "File no found" :
message);
case 403:
return new ForbiddenAccessException(message == null ? "Forbidden access" : message);
}
return errorDecoder.decode(s, response);
}
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
public static class ExceptionMessage{
private String timestamp;
private int status;
private String error;
private String message;
private String path;
}
}
If you're like me and really just want the content out of a failed Feign call without all these custom decoders and boilerplate, there is a hacky way do this.
If we look at FeignException when it is being created and a response body exists, it assembles the exception message like so:
if (response.body() != null) {
String body = Util.toString(response.body().asReader());
message += "; content:\n" + body;
}
Therefore if you're after the response body, you can just pull it out by parsing the Exception message since it is delimited by a newline.
String[] feignExceptionMessageParts = e.getMessage().split("\n");
String responseContent = feignExceptionMessageParts[1];
And if you want the object, you can use something like Jackson:
MyResponseBodyPojo errorBody = objectMapper.readValue(responseContent, MyResponseBodyPojo.class);
I do not claim this is a smart approach or a best practice.
The original message is within the Response body, as already answered. However, we can reduce the amount of boilerplate using Java 8 Streams to read it:
public class CustomErrorDecoder implements ErrorDecoder {
private final ErrorDecoder errorDecoder = new Default();
#Override
public Exception decode(String s, Response response) {
String body = "4xx client error";
try {
body = new BufferedReader(response.body().asReader(StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
} catch (IOException ignore) {}
switch (response.status()) {
case 404:
return new FileNotFoundException(body);
case 403:
return new ForbiddenAccessException(body);
}
return errorDecoder.decode(s, response);
}
}
Some refactoring and code style on accepted answer:
#Override
#SneakyThrows
public Exception decode(String methodKey, Response response) {
String message;
try (Reader reader = response.body().asReader()) {
String result = StringUtils.toString(reader);
message = mapper.readValue(result, ErrorResponse.class).getMessage();
}
if (response.status() == 401) {
return new UnauthorizedException(message == null ? response.reason() : message);
}
if (response.status() == 403) {
return new ForbiddenException(message == null ? response.reason() : message);
}
return defaultErrorDecoder.decode(methodKey, response);
}
I need to integrate on Liferay 6.2 GA6 a SSO from a web application that provide info by oAuth
A native support doesn't exist.
My problem is to create the automatic login on Liferay (after the user creation or if the user already exists). Any help ?
You have to create a hook where you create an AutoLogin class that extends BaseAutoLogin. Read the oAuth documentation and write a login logic in that hook, then set it in auto.login.hooks property in portal-ext.properties(properties reference). Then you will have to create a filter that extends BasePortalFilter and implemets processFilter method. You can model on CASFilter and CASAutologin
override portal.properties adding
auto.login.hooks=com.yourpackage.hook.MyAutoLogin
Create the class:
package com.yourpackage.hook;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.model.User;
import com.liferay.portal.security.auth.AutoLogin;
import com.liferay.portal.security.auth.AutoLoginException;
import com.liferay.portal.service.UserLocalServiceUtil;
import com.liferay.portal.util.PortalUtil;
//based on example
// https://bitbucket.org/brandizzi/liferay-examples/src/a41d71eba8f2fb2d4272a3ce8f393e77cec41d60/unsafe-login-hook/docroot/WEB-INF/src/br/brandizzi/adam/liferay/unsecure/UnsecureAutoLogin.java?at=default&fileviewer=file-view-default
public class MyAutoLogin implements AutoLogin {
#Override
public String[] login(HttpServletRequest request,HttpServletResponse response) throws AutoLoginException {
HttpSession session = request.getSession();
String emailAddress = (String) session.getAttribute("LIFERAY_SHARED_EMAIL");
if (emailAddress == null || emailAddress.isEmpty())
return null;
long companyId = PortalUtil.getCompanyId(request);
User user = null;
try {
user = UserLocalServiceUtil.getUserByEmailAddress(companyId, emailAddress);
} catch (PortalException | SystemException e) {
e.printStackTrace();
}
String redirect = ParamUtil.getString(request, "redirect");
if (Validator.isNotNull(redirect)) {
request.setAttribute(AutoLogin.AUTO_LOGIN_REDIRECT_AND_CONTINUE,PortalUtil.escapeRedirect(redirect));
}
String[] credentials = new String[3];
credentials[0] = String.valueOf(user.getUserId());
credentials[1] = user.getPassword();
credentials[2] = String.valueOf(user.isPasswordEncrypted());
// credentials[2] = Boolean.FALSE.toString();
return credentials;
}
#Override
public String[] handleException(HttpServletRequest arg0,
HttpServletResponse arg1, Exception arg2)
throws AutoLoginException {
System.out.println("AutoLogin handleException ");
return null;
}
}
create an other class with the static methods:
public static JSONObject doSSO(String firstname, String surname, String email, String username,String accessToken, ActionRequest actionRequest, ActionResponse actionResponse){
JSONObject jsonResp = JSONFactoryUtil.createJSONObject();
//Get default Liferay company
String webId = new String("liferay.com");
Company company = null;
try {
company = CompanyLocalServiceUtil.getCompanyByWebId(webId);
} catch (PortalException | SystemException e) {
e.printStackTrace();
}
System.out.println("email "+email);
User currentUser = null;
try {
currentUser = UserLocalServiceUtil.getUserByEmailAddress(company.getCompanyId(), email);
} catch (SystemException | PortalException e) {
System.out.println("User to create");
}
if (Validator.isNull(currentUser)){
long newUserId = 0;
try {
jsonResp = addNewUser( firstname, surname, email, username );
} catch (Exception e) {
e.printStackTrace();
}
String newUserIdS = jsonResp.getString("newUserId");
newUserId = Long.valueOf(newUserIdS);
try {
currentUser = UserLocalServiceUtil.fetchUser(newUserId);
} catch (SystemException e) {
e.printStackTrace();
}
notifyAuthorAboutInvited(email, currentUser);
}
setExistingUserOnSession( actionRequest,currentUser, accessToken);
//Login the user
HttpServletRequest request = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(actionRequest));
HttpServletResponse response = PortalUtil.getHttpServletResponse(actionResponse);
MyAutoLogin myLogin = new MyAutoLogin();
try {
myLogin.login(request, response);
jsonResp.put("message","OK - User logged on Liferay");
} catch (AutoLoginException e1) {
e1.printStackTrace();
}
//set Token on customfield
//remember to set permission guest to view and update
ServiceContext serviceContext = null;
try {
serviceContext = ServiceContextFactory.getInstance(User.class.getName(), actionRequest);
} catch (PortalException | SystemException e) {
e.printStackTrace();
}
Map<String,Serializable> expandoBridgeAttributes = new HashMap<String, Serializable>();
expandoBridgeAttributes.put("token", accessToken);
serviceContext.setExpandoBridgeAttributes(expandoBridgeAttributes);
currentUser.setExpandoBridgeAttributes(serviceContext);
try {
UserLocalServiceUtil.updateUser(currentUser);
} catch (SystemException e) {
e.printStackTrace();
}
String userToken =currentUser.getExpandoBridge().getAttribute("token").toString();
//System.out.println("doSSO accessToken dopo "+userToken);
return jsonResp;
}
and:
private static void setExistingUserOnSession(ActionRequest actionRequest,User user, String accessToken) {
HttpServletRequest req = PortalUtil.getHttpServletRequest(actionRequest);
HttpSession session = req.getSession();
session.setAttribute("LIFERAY_SHARED_EMAIL", user.getEmailAddress());
}
I want to post to an url https://host:0101 with a request body. I have done this with non-ssl, http, but having trouble with https.
I have both the trust store (JKS) and keystore (PKCS12)'s full path, and their passwords as properties in a .properties file.
What i have to far is:
public sendPost () throws Exception {
SSLContext sslContext = getContext();
SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(factory).build();
HttpPost post = new HttpPost("https://host:0101/post");
StringEntity entity = new StringEntity(jsonData);
post.setEntity(entity);
response=client.execute(request);
responseCode = response.getStatusLine().getStatusCode();
}
public SSLContext getContext() throws Exception {
KeyStore keyStore = KeyStore.getInstance("JKS");
FileInputStream instream = new FileInputStream(new File(PATH_TO_KEYSTORE));
try {
keyStore.load(instream, "password".toCharArray());
}finally {instream.close()}
return SSLContexts.custom().loadTrustMaterial(keyStore).build();
}
I am testing this by running a Junit test just to verify that it works before deploying.
#Test
public void test() throws Exception {
int responseCode = entityUnderTest.sendPost();
assertEquals(200, responseCode);
}
The error is at line: response=client.execute(request); with the HttpHostConnectException
Failed: Connection Refused
Is the service available through HTTPS? The connection refused error occurs when there is some problem with the availability of your service.
This could be caused by a lot of problems:
your service is not running
your service is not available through HTTPS
a proxy/routing error (does your test system reach the host and port?)
If there was a problem with the authentication you would get a different message (eg: SSLPeerUnverifiedException, SSLHandshakeException).
This is working for me.. try it
Here is the post method
public static CookieManager msCookieManager = null;
private boolean isPinBuild=false;
public static String[] post(Context context, String Url, List<NameValuePair> values, List<NameValuePair> header_list)
throws ConnectTimeoutException {
String[] result = { "", "" };
try {
URL url = new URL(Url);
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
Log.i("TAG_URL : ", Url);
if (isPinBuild) {
KeyPinStore keystore = KeyPinStore.getInstance(context);
javax.net.ssl.SSLSocketFactory factory = keystore.getContext().getSocketFactory();
SSLSocket socket = (SSLSocket)factory.createSocket();
socket.setEnabledCipherSuites(new String[]{"RC4-MD5", "DES-CBC-SHA", "DES-CBC3-SHA"});
socket.setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
socket.setSoTimeout(60000);
urlConnection.setSSLSocketFactory(factory);
} else {
KeyUnPinStore keystore = KeyUnPinStore.getInstance(context);
javax.net.ssl.SSLSocketFactory factory = keystore.getContext().getSocketFactory();
SSLSocket socket = (SSLSocket)factory.createSocket();
socket.setEnabledCipherSuites(new String[]{"RC4-MD5", "DES-CBC-SHA", "DES-CBC3-SHA"});
socket.setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
socket.setSoTimeout(60000);
urlConnection.setSSLSocketFactory(factory);
}
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER;
urlConnection.setRequestMethod("POST");
urlConnection.setConnectTimeout(connection_timeout);
urlConnection.setHostnameVerifier(hostnameVerifier);
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
for (NameValuePair header : header_list) {
urlConnection.addRequestProperty(header.getName(), header.getValue());
}
if (msCookieManager == null) {
msCookieManager = new CookieManager();
}
if (msCookieManager != null && msCookieManager.getCookieStore().getCookies().size() > 0) {
urlConnection.setRequestProperty(COOKIE, TextUtils.join(";", msCookieManager.getCookieStore().getCookies()));
}
Log.i("TAG_POST_COOKIE : ", msCookieManager.getCookieStore().getCookies().toString());
String postData = "";
for (NameValuePair value : values) {
postData = postData + value.getName() + "=" + URLEncoder.encode(value.getValue(), "UTF-8") + "&";
}
if (!TextUtils.isEmpty(postData) && postData.length() > 2) {
postData = postData.substring(0, postData.length() - 1);
}
Log.i("TAG_POSTDATA : ", postData);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
urlConnection.setFixedLengthStreamingMode(postData.getBytes().length);
PrintWriter out = new PrintWriter(urlConnection.getOutputStream());
out.print(postData);
out.close();
// always check HTTP response code first
int responseCode = urlConnection.getResponseCode();
result[0] = responseCode + "";
if (responseCode == HttpURLConnection.HTTP_OK) {
// Get Response
InputStream is = urlConnection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer response = new StringBuffer();
while ((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
Map<String, List<String>> headerFields = urlConnection.getHeaderFields();
List<String> cookiesHeader = headerFields.get(COOKIES_HEADER);
/*if (cookiesHeader != null) {
for (String cookie : cookiesHeader) {
if (HttpCookie.parse(cookie).get(0).toString().contains(JSESSIONID)) {
msCookieManager.getCookieStore().add(null, HttpCookie.parse(cookie).get(0));
}
}
}*/
if (!TextUtils.isEmpty(response)) {
result[0] = HttpConnectionUrl.RESPONSECODE_REQUESTSUCCESS;
result[1] = response.toString();
Log.i("TAG_RESPONSE : ", result[1]);
}
}
} catch (UnsupportedEncodingException e) {
result[0] = HttpConnectionUrl.RESPONSECODE_CONNECTIONTIMEOUT;
e.printStackTrace();
} catch (ClientProtocolException e) {
result[0] = HttpConnectionUrl.RESPONSECODE_CONNECTIONTIMEOUT;
e.printStackTrace();
} catch (ConnectTimeoutException e) {
result[0] = HttpConnectionUrl.RESPONSECODE_CONNECTIONTIMEOUT;
e.printStackTrace();
} catch (IOException e) {
result[0] = HttpConnectionUrl.RESPONSECODE_CONNECTIONTIMEOUT;
e.printStackTrace();
} catch (Exception e) {
result[0] = HttpConnectionUrl.RESPONSECODE_CONNECTIONTIMEOUT;
e.printStackTrace();
}
return result;
}
here isPinBuild variable use for you have any certificate file or not. If you use any trusted certificate then set true.
Here the KeyPinStore class
public class KeyPinStore {
private static Context context = null;
private static KeyPinStore instance = null;
private SSLContext sslContext = SSLContext.getInstance("SSLv3");
//private SSLContext sslContext = SSLContext.getInstance("TLS");
public static synchronized KeyPinStore getInstance(Context mContext) throws CertificateException, IOException, KeyStoreException,
NoSuchAlgorithmException, KeyManagementException {
if (instance == null) {
context = mContext;
instance = new KeyPinStore();
}
return instance;
}
private KeyPinStore() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// randomCA.crt should be in the Assets directory
InputStream caInput = new BufferedInputStream(context.getAssets().open("yourCertificate.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
// SSLContext context = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
}
public SSLContext getContext() {
return sslContext;
}
}
and KeyUnpinStore class
public class KeyUnPinStore {
private static Context context = null;
private static KeyUnPinStore instance = null;
private SSLContext sslContext = SSLContext.getInstance("TLS");
public static synchronized KeyUnPinStore getInstance(Context mContext) throws CertificateException, IOException, KeyStoreException,
NoSuchAlgorithmException, KeyManagementException {
if (instance == null) {
context = mContext;
instance = new KeyUnPinStore();
}
return instance;
}
private KeyUnPinStore() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
// Create all-trusting host name verifier
// Create an SSLContext that uses our TrustManager
// SSLContext context = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
}
public SSLContext getContext() {
return sslContext;
}
}
Why don't you try using httpbin? It's an external resource that's guaranteed to work. For example:
import java.io.IOException;
import java.net.URI;
import net.minidev.json.JSONObject;
import net.minidev.json.JSONValue;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class Post {
public static void main(String[] args) throws Exception {
HttpClient client = new DefaultHttpClient();
int result = post(client, new URI("https://httpbin.org/post"), (JSONObject)JSONValue.parse("{'answer':42}"));
System.err.println(result);
}
public static int post(HttpClient httpClient, URI url, JSONObject content) throws IOException {
final HttpPost post = new HttpPost(url);
post.addHeader("Content-type", ContentType.APPLICATION_JSON.getMimeType());
post.setEntity(new StringEntity(content.toString(), ContentType.APPLICATION_JSON));
final HttpResponse response = httpClient.execute(post);
EntityUtils.consumeQuietly(response.getEntity());
return response.getStatusLine().getStatusCode();
}
}
Assuming that you have generated public/private keypairs using java "keytool" and both trustStore & keyStores are configured properly at client-side & in HOST container(in case of Tomcat server.xml).
In Method:"sendPost()", you may like to get SSL-Connection as follows:
try {
String endpoint="https://host:0101/post";
URL url = new URL(endpoint);
HttpsURLConnection conn = getConnection(url, "POST", uname, passwd);
conn.connect();
writeBody(conn);
catch(Exception e) { throw new RuntimeException(e); }
conn.disconnect();
}
catch(Exception e) { throw new RuntimeException(e); }
private void writeBody(HttpsURLConnection conn) {
try {
String pairs = "who=Freddy&what=Avoid Friday nights if possible.";
OutputStream out = conn.getOutputStream();
out.write(pairs.getBytes());
out.flush();
}
catch(Exception e) { throw new RuntimeException(e); }
}
package com.google.serviceacc;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.JSONException;
import org.json.JSONObject;
public class GoogleServiceAccount<E> {
static String keyAlias = "privatekey";
public static byte[] signData(byte[] data, PrivateKey privateKey) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException
{
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
/*public static String encodeBase64(byte[] rawData)
{
byte[] data = Base64.encodeBase64(rawData);
return data.toString();
}*/
private static PrivateKey getPrivateKey(String keyFile, String password)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException
{
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(new FileInputStream(keyFile), password.toCharArray());
PrivateKey privateKey = (PrivateKey) keystore.getKey(keyAlias, password.toCharArray());
return privateKey;
}
public static void main(String[] args) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, CertificateException, IOException {
String keystoreLoc = "C:/Users/xyz/Downloads/b5b400df17628d8.p12";
String password = "notasecret";
String jwtStr=null;
String jwtClaimStr=null;
PrivateKey privateKey=null;
JSONObject jwtHeader=new JSONObject();
try {
jwtHeader.put("alg","RS256");
jwtHeader.put("typ","JWT");
jwtStr= jwtHeader.toString();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encodedHeader = Base64.encodeBase64(jwtStr.getBytes("UTF-8"));
System.out.println("Original HEaderString: " + jwtStr );
System.out.println("Base64 Encoded HeaderString : " + new String(encodedHeader));
JSONObject jwtClaimSet= new JSONObject();
try {
jwtClaimSet.put("iss", "client_id_email#developer.gserviceaccount.com");
jwtClaimSet.put("scope", "https://www.googleapis.com/auth/devstorage.readonly");
jwtClaimSet.put("aud", "https://accounts.google.com/o/oauth2/token");
jwtClaimSet.put("exp", "1328554385");
jwtClaimSet.put("iat", "1328550785");
jwtClaimStr=jwtClaimSet.toString();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encodedClaimSet=Base64.encodeBase64(jwtClaimStr.getBytes("UTF-8"));
System.out.println("Original ClaimSet String:"+jwtClaimStr);
System.out.println("Base64 Encoded ClaimSet:"+ new String(encodedClaimSet) );
StringBuffer token = new StringBuffer();
token.append(Base64.encodeBase64(jwtStr.getBytes("UTF-8")));
token.append(".");
token.append(Base64.encodeBase64(jwtClaimStr.getBytes("UTF-8")));
privateKey= getPrivateKey(keystoreLoc, password);
byte[] sig = signData(token.toString().getBytes("UTF-8"), privateKey);
byte[] signedPayload =Base64.encodeBase64(sig);
token.append(".");
token.append(signedPayload);
HttpClient client = new HttpClient();
PostMethod method = new PostMethod("https://accounts.google.com/o/oauth2/token");
method.addRequestHeader("Content-Type", "application/x-www-form-urlencoded");
method.addParameter("grant_type","urn:ietf:params:oauth:grant-type:jwt-bearer");
System.out.println("printing Token.toString():"+token.toString());
method.addParameter("assertion",token.toString());
System.out.println("Printing QuerString:"+method.getQueryString());
System.out.println("Printing request char set:"+method.getRequestCharSet());
try {
int responseCode=client.executeMethod(method);
System.out.println(responseCode);
System.out.println(method.getResponseBodyAsString());
System.out.println(method.getURI());
} catch (HttpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
If i try to execute the above code i' am getting
{
"error" : "invalid_grant"
}
I created a service account and was able to download private key through the above code.But when i try to exute the request to retrieve the accesstoken iam getting invalid grant error
Do I need to add something?
I Finally got the output!!!!
Updated code is:
package com.voxmobili.sng.cnx.gmail.sync;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.JSONException;
import org.json.JSONObject;
public class GoogleServiceAccount<E> {
static String keyAlias = "privatekey";
public static byte[] signData(byte[] data, PrivateKey privateKey) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException
{
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
public static String encodeBase64(byte[] rawData)
{
byte[] data = Base64.encodeBase64(rawData);
return data.toString();
}
private static PrivateKey getPrivateKey(String keyFile, String password)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException
{
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(new FileInputStream(keyFile), password.toCharArray());
PrivateKey privateKey = (PrivateKey) keystore.getKey(keyAlias, password.toCharArray());
return privateKey;
}
public static void main(String[] args) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, CertificateException, IOException {
String keystoreLoc = "C:/Users/xyz/Downloads/b5b400df17628d8.p12";
String password = "notasecret";
String jwtHeaderStr=null;
String jwtClaimStr=null;
PrivateKey privateKey=null;
//JWT HEADER
JSONObject jwtHeader=new JSONObject();
try {
jwtHeader.put("alg","RS256");
jwtHeader.put("typ","JWT");
jwtHeaderStr= jwtHeader.toString();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encodedHeader = Base64.encodeBase64(jwtHeaderStr.getBytes("UTF-8"));
System.out.println("Original HEaderString: " + jwtHeaderStr );
System.out.println("Base64 Encoded HeaderString : " + new String(encodedHeader));
//JWT CLAIMSET
JSONObject jwtClaimSet= new JSONObject();
long iat = (System.currentTimeMillis()/1000)-60;
long exp = iat + 3600;
try {
jwtClaimSet.put("iss", "4459#developer.gserviceaccount.com");
jwtClaimSet.put("scope", "https://www.googleapis.com/auth/calendar.readonly");
jwtClaimSet.put("aud", "https://accounts.google.com/o/oauth2/token");
jwtClaimSet.put("exp", +exp);
jwtClaimSet.put("iat",+iat);
jwtClaimStr=jwtClaimSet.toString();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encodedClaimSet=Base64.encodeBase64(jwtClaimStr.getBytes("UTF-8"));
System.out.println("Original ClaimSet String:"+jwtClaimStr);
System.out.println("Base64 Encoded ClaimSet:"+ new String(encodedClaimSet) );
StringBuffer token = new StringBuffer();
token.append(new String(encodedHeader));
token.append(".");
token.append(new String(encodedClaimSet));
//JWT SIGNATURE
privateKey= getPrivateKey(keystoreLoc, password);
byte[] sig = signData(token.toString().getBytes("UTF-8"), privateKey);
byte[] encodedSig=Base64.encodeBase64(sig);
System.out.println("Signature before encoding:"+ new String(encodedSig));
String signedPayload =encodeBase64(sig);
//System.out.println("Signature before encoding:"+signedPayload);
token.append(".");
//token.append(signedPayload);
token.append(new String(encodedSig));
HttpClient client = new HttpClient();
PostMethod method = new PostMethod("https://accounts.google.com/o/oauth2/token");
method.addRequestHeader("Content-Type", "application/x-www-form-urlencoded");
method.addParameter("grant_type","urn:ietf:params:oauth:grant-type:jwt-bearer");
System.out.println("printing Token.toString():"+token.toString());
method.addParameter("assertion",token.toString());
try {
int responseCode=client.executeMethod(method);
System.out.println(responseCode);
System.out.println(method.getResponseBodyAsString());
System.out.println(method.getURI());
} catch (HttpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}