Spring security with google Oauth - java

I have been working on a web application in which I have used Google oauth and Spring MVC. I have implemented the google oauth in which the user is directed to the desired URL if the user is authenticated by the google oauth. For achieving this functionality i have used the google GogleAuthHelper class. Here is my code
package com.mob.googleoauth;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.json.JSONException;
import org.json.JSONObject;
import com.google.api.client.auth.oauth2.AuthorizationCodeRequestUrl;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.auth.oauth2.TokenResponseException;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeRequestUrl;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
public final class GoogleAuthHelper {
private static final String CLIENT_ID = "";
private static final String CLIENT_SECRET = " ";
/**
* Callback URI that google will redirect to after successful authentication
*/
private static final String CALLBACK_URI = "http://localhost:8080/orgchart/oauthRedirect";
// private static final String HD = " ";
// start google authentication constants
private static final Iterable<String> SCOPE = Arrays
.asList("https://www.googleapis.com/auth/userinfo.profile;https://www.googleapis.com/auth/userinfo.email"
.split(";"));
private static final String USER_INFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo";
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
// end google authentication constants
private String stateToken;
private final GoogleAuthorizationCodeFlow flow;
/**
* Constructor initializes the Google Authorization Code Flow with CLIENT
* ID, SECRET, and SCOPE
*/
public GoogleAuthHelper() {
System.out.println("google auth helper called");
flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT,
JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, SCOPE).build();
flow.newAuthorizationUrl().setApprovalPrompt("force").setAccessType("offline");
// AuthorizationCodeRequestUrl authorizationUrl = flow
// .newAuthorizationUrl().setRedirectUri(CALLBACK_URI)
// .setApprovalPrompt("force").setAccessType("offline");
generateStateToken();
}
/**
* Builds a login URL based on client ID, secret, callback URI, and scope
*/
public String buildLoginUrl() {
System.out.println("building uri called");
final GoogleAuthorizationCodeRequestUrl url = flow
.newAuthorizationUrl();
return url.setRedirectUri(CALLBACK_URI).setState(stateToken).build();
}
/**
* Generates a secure state token
*/
private void generateStateToken() {
System.out.println("generated token called");
SecureRandom sr1 = new SecureRandom();
// System.out.println(sr1);
stateToken = "google;" + sr1.nextInt();
}
/**
* Accessor for state token
*/
public String getStateToken() {
System.out.println("gettoken called");
return stateToken;
}
/**
* Expects an Authentication Code, and makes an authenticated request for
* the user's profile information
*
* #return JSON formatted user profile information
* #param authCode
* authentication code provided by google
* #throws JSONException
*/
#SuppressWarnings("unchecked")
public List getUserInfoJson(final String authCode,HttpSession session) throws IOException,
JSONException {
List ls = new ArrayList();
try{
System.out.println("getuserinfojson called");
final GoogleTokenResponse response = flow.newTokenRequest(authCode)
.setRedirectUri(CALLBACK_URI).execute();
session.setAttribute("userToken", response.getAccessToken());
final Credential credential = flow.createAndStoreCredential(response,
null);
final HttpRequestFactory requestFactory = HTTP_TRANSPORT
.createRequestFactory(credential);
// Make an authenticated request
final GenericUrl url = new GenericUrl(USER_INFO_URL);
final HttpRequest request = requestFactory.buildGetRequest(url);
request.getHeaders().setContentType("application/json");
final String jsonIdentity = request.execute().parseAsString();
// System.out.println(jsonIdentity);
JSONObject object = new JSONObject(jsonIdentity);
String email = object.getString("email");
String name = object.getString("name");
String picture = object.getString("picture");
ls.add(email);
ls.add(name);
ls.add(picture);
}
catch(NullPointerException e)
{
throw e;
}
catch (TokenResponseException e) {
throw e;
}
return ls;
}
}
ABove works fine for one time that is authenticating the user and redirecting to the given URL but after that the application is not secure. That is URL in my application are not secure. For this I want to include the spring security along with google oauth. Is there any good detailed example to do that. I have searched the google and have not been successful. I want a good working example for spring security and google oauth.
thanks for nay help

Here I am giving you few links. It was helpful for me for understanding purpose. Hope it would help you too.
On this link you can go for your desired category. Considering Spring Security for OAuth, this you can check.
http://docs.spring.io/spring-security/oauth/
http://www.hsc.com/Portals/0/Uploads/Articles/WP_Securing_RESTful_WebServices_OAuth2635406646412464000.pdf
http://porterhead.blogspot.in/2014/05/securing-rest-services-with-spring.html

Related

how to provide custom uri and port to send SMS to phone number using twilio sdk library in java?

I have to send SMS on phone number from Java function.
I am using below sample code from Twilio site for POC and it's working fine without any issue.
public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXX";
public static final String AUTH_TOKEN = "XXXXXXXXXXX";
public static void main(String[] args) {
Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
Message message = Message.creator(new PhoneNumber("+1111111111"),
new PhoneNumber("XXXXX"),
"This is the ship that made the Kessel Run in fourteen parsecs?").create();
System.out.println(message.getSid());
}
Now I have to pass custom uri which is DP URI with custom port, which is working fine, when i am testing with postman.
but how can i fit here custom URI in this java code?
or do i have to use different code?
or do i have to create my own rest client to work with custom uri?
NOTE: I am using implementation 'com.twilio.sdk:twilio:8.18.0' in build.gradle file. i checked all available options of creator constructor. None of options takes from Number, To Number, Body and URI.
Twilio developer evangelist here.
To access the API using the Twilio Java SDK through a proxy requires you to provide an HTTP Client that uses the proxy. This is documented here in custom documents for the Twilio Java library.
The full code from that article is:
import com.twilio.http.HttpClient;
import com.twilio.http.NetworkHttpClient;
import com.twilio.http.TwilioRestClient;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
public class ProxiedTwilioClientCreator {
private String username;
private String password;
private String proxyHost;
private int proxyPort;
private HttpClient httpClient;
/**
* Constructor for ProxiedTwilioClientCreator
* #param username
* #param password
* #param proxyHost
* #param proxyPort
*/
public ProxiedTwilioClientCreator(String username, String password, String proxyHost, int proxyPort) {
this.username = username;
this.password = password;
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
}
/**
* Creates a custom HttpClient based on default config as seen on:
* {#link com.twilio.http.NetworkHttpClient#NetworkHttpClient() constructor}
*/
private void createHttpClient() {
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(10000)
.setSocketTimeout(30500)
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setDefaultMaxPerRoute(10);
connectionManager.setMaxTotal(10*2);
HttpHost proxy = new HttpHost(proxyHost, proxyPort);
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
clientBuilder
.setConnectionManager(connectionManager)
.setProxy(proxy)
.setDefaultRequestConfig(config);
// Inclusion of Twilio headers and build() is executed under this constructor
this.httpClient = new NetworkHttpClient(clientBuilder);
}
/**
* Get the custom client or builds a new one
* #return a TwilioRestClient object
*/
public TwilioRestClient getClient() {
if (this.httpClient == null) {
this.createHttpClient();
}
TwilioRestClient.Builder builder = new TwilioRestClient.Builder(username, password);
return builder.httpClient(this.httpClient).build();
}
}
Which you can then use like this to, for example, send an SMS message:
// Install the Java helper library from twilio.com/docs/java/install
import com.twilio.Twilio;
import com.twilio.http.TwilioRestClient;
import com.twilio.rest.api.v2010.account.Message;
import com.twilio.type.PhoneNumber;
import io.github.cdimascio.dotenv.Dotenv;
public class Example {
public static void main(String args[]) {
Dotenv dotenv = Dotenv.configure()
.directory(".")
.load();
String ACCOUNT_SID = dotenv.get("ACCOUNT_SID");
String AUTH_TOKEN = dotenv.get("AUTH_TOKEN");
String PROXY_HOST = dotenv.get("PROXY_HOST");
int PROXY_PORT = Integer.parseInt(dotenv.get("PROXY_PORT"));
Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
ProxiedTwilioClientCreator clientCreator = new ProxiedTwilioClientCreator(
ACCOUNT_SID, AUTH_TOKEN, PROXY_HOST, PROXY_PORT);
TwilioRestClient twilioRestClient = clientCreator.getClient();
Twilio.setRestClient(twilioRestClient);
Message message = Message.creator(new PhoneNumber("+15558675310"),
new PhoneNumber("+15017122661"), "Hey there!").create();
System.out.println(message.getSid());
}
}

Why does acquiring an Azure AD token by refresh token have no signing algorithm?

When I get a token by authorization code (authContext.acquireTokenByAuthorizationCode), I get a JWT (idToken) that is signed and has the proper headers:
{
"typ": "JWT",
"alg": "RS256",
"x5t": "wLLmYfsqdQuWtV_-hnVtDJJZM3Q",
"kid": "wLLmYfsqdQuWtV_-hnVtDJJZM3Q"
}
but when I use the refresh token to get a new token (authContext.acquireTokenByRefreshToken(...)), it returns an unsigned JWT:
{
"typ": "JWT",
"alg": "none"
}
How do I get it to give me a signed JWT?
return authContext.acquireTokenByRefreshToken(
refreshToken,
new ClientCredentials(
clientId,
clientSecret
),
null
);
I did not reproduce your issue on my side. I followed this tutorial to get Authentication code and acquire access token and refresh token with below code successfully. Please refer to it.
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import java.net.URI;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class GetTokenByAuthenticationCode {
private static final String APP_ID = "***";
private static final String APP_SECRET = "***";
private static final String REDIRECT_URI = "http://localhost:8080";
private static final String tenant = "***";
public static void main(String[] args) throws Exception {
String authority = "https://login.microsoftonline.com/" + tenant + "/oauth2/authorize";
ExecutorService service = Executors.newFixedThreadPool(1);
String code = "***";
AuthenticationContext context = new AuthenticationContext(authority, true, service);
URI url = new URI(REDIRECT_URI);
Future<AuthenticationResult> result = context.acquireTokenByAuthorizationCode(
code,
url,
new ClientCredential(APP_ID, APP_SECRET),
null
);
String token = result.get().getAccessToken();
System.out.println(token);
String refreshToken = result.get().getRefreshToken();
System.out.println(refreshToken);
Future<AuthenticationResult> result1 = context.acquireTokenByRefreshToken(
refreshToken,
new ClientCredential(APP_ID, APP_SECRET),
null
);
String tokenNew = result1.get().getAccessToken();
String refreshTokenNew = result1.get().getRefreshToken();
System.out.println(tokenNew);
System.out.println(refreshTokenNew);
}
}
Decode:
Update Answer:
Firstly, sorry for the mistake. I replaced getIdToken with getAccessToken, the result is as same as you.Then I searched the response parameters in Authorize access to Azure Active Directory web applications using the OAuth 2.0 code grant flow, you could find the statement of id_token parameter.
An unsigned JSON Web Token (JWT) representing an ID token. The app can
base64Url decode the segments of this token to request information
about the user who signed in. The app can cache the values and display
them, but it should not rely on them for any authorization or security
boundaries.
So, the id token just a segment which can't be relied on. If you want to get the complete id token, please refer to the openId flow.

Akamai CCU V3 Fast Purge implementation with JAVA project or AEM

Has anyone tried integrating there java code from CCU V2 to CCU V3 with fast purge. I read the documentation but unable to understand what needs to be done in case of a java based project. After we have configured the client in Akamai console how do we write the code to access and clear.
Any help is highly appreciated.
Thanks,
Tushar
The general approach is to write some code that makes an HTTP request to the fast purge endpoint.
Here is some an example:
import com.akamai.edgegrid.auth.*;
//other imports
public void callAkamaiFastPurgeForUrls(Set<String> urlsToPurge) throws URISyntaxException, IOException, RequestSigningException {
if(!urlsToPurge.isEmpty()) {
int status;
String json = getPurgeJson(urlsToPurge);
HttpRequest signedRequest = getHttpRequest(json, compProperty);
HttpResponse response = signedRequest.execute();
status = response.getStatusCode();
if (status == 201) {
//handle success responses as you see fit
} else {
//handle non-success responses as you see fit
}
}
}
private static String getPurgeJson(Set<String> pathsToPurge) {
//your code to turn the list of urls into JSON in this format:
//{"objects":["https://www.yourdomain.com/page1.html","https://www.yourdomain.com/page2.html"]}
return //JSON string such as the example above
}
private HttpRequest getHttpRequest(String json, Dictionary<String, Object> dispatcherAndAkamaiServletProperties) throws URISyntaxException, IOException, RequestSigningException {
String hostName = yourCodeToFetchConfigValues("hostname");
String accessToken = yourCodeToFetchConfigValues("accesstoken");
String clientToken = yourCodeToFetchConfigValues("clienttoken");
String clientSecret = yourCodeToFetchConfigValues("clientsecret");
String apiUrl = yourCodeToFetchConfigValues("apiurl");
String proxyServer = yourCodeToFetchConfigValues("proxyhostakamai");
int proxyPort = yourCodeToFetchConfigValues("proxyport");
HttpTransport httpTransport = new NetHttpTransport.Builder()
.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyServer, proxyPort))).build();
HttpRequestFactory requestFactory = httpTransport.createRequestFactory();
URI uri = new URI(HTTPS, hostName, apiUrl, null, null);
HttpContent body = new ByteArrayContent("application/json", json.getBytes());
HttpRequest request = requestFactory.buildPostRequest(new GenericUrl(uri), body);
HttpHeaders headers = request.getHeaders();
headers.set("Host", hostName);
ClientCredential credential = new DefaultCredential(clientToken, accessToken, clientSecret);
RequestSigner signer = new EdgeGridV1Signer(Collections.emptyList(), 1024 * 2);
return signer.sign(request, credential);
}
In addition you will likely need to update your truststore to include the certificates of the Akamai endpoints you are calling so that the SSL communication can happen.
What #Shawn has answered is mostly correct. Though you would like to have more things in plate like your custom replication agent, a custom content builder and a transport handler if you are integrating it with AEM. Also, there can be few dependency issues as well.
If you need help with all these, you can refer to below article:
https://www.linkedin.com/pulse/akamai-cache-purge-aem-through-java-code-shubham-saxena/
For a transport handler you can use below snippet:
package com.myproject.bundle.core.services.impl;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.http.entity.ContentType;
import org.apache.jackrabbit.util.Base64;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.akamai.edgegrid.signer.ClientCredential;
import com.akamai.edgegrid.signer.exceptions.RequestSigningException;
import com.akamai.edgegrid.signer.googlehttpclient.GoogleHttpClientEdgeGridRequestSigner;
import com.day.cq.replication.AgentConfig;
import com.day.cq.replication.ReplicationActionType;
import com.day.cq.replication.ReplicationException;
import com.day.cq.replication.ReplicationResult;
import com.day.cq.replication.ReplicationTransaction;
import com.day.cq.replication.TransportContext;
import com.day.cq.replication.TransportHandler;
import com.myproject.bundle.core.configuration.BaseConfigurationService;
import com.myproject.bundle.core.constants.MyConstants;
import com.myproject.bundle.core.search.services.MyProjectConfigurationService;
import com.google.api.client.http.ByteArrayContent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.apache.ApacheHttpTransport;
/**
* Transport handler to send test and purge requests to Akamai and handle
* responses. The handler sets up basic authentication with the user/pass from
* the replication agent's transport config and sends a GET request as a test
* and POST as purge request. A valid test response is 200 while a valid purge
* response is 201.
*
* The transport handler is triggered by setting your replication agent's
* transport URL's protocol to "akamai://".
*
* The transport handler builds the POST request body in accordance with
* Akamai's Fast Purge REST API {#link https://developer.akamai.com/api/core_features/fast_purge/v3.html}
* using the replication agent properties.
*/
#Component(service = TransportHandler.class, immediate = true)
public class AkamaiTransportHandler implements TransportHandler {
/**The Solr Server Configuration Service.*/
#Reference
MyProjectConfigurationService myProjectConfigurationService;
#Reference
BaseConfigurationService baseConfigurationService;
/**Logger Instantiation for Akamai Transport Handler*/
private static final Logger LOGGER = LoggerFactory.getLogger(AkamaiTransportHandler.class);
/** Protocol for replication agent transport URI that triggers this transport handler. */
private static final String AKAMAI_PROTOCOL = "akamai://";
/**Config Pid for Akamai Flush*/
private static final String AKAMAI_FLUSH_CONFIG_PID = "com.myproject.bundle.core.configuration.AkamaiFlushConfiguration";
/** Replication agent type property name. Valid values are "arl" and "cpcode". */
private static final String PROPERTY_AKAMAI_TYPE = "type";
/** Replication agent multifield CP Code property name.*/
private static final String PROPERTY_AKAMAI_CP_CODES = "4321xxx";
/** Replication agent domain property name. Valid values are "staging" and "production". */
private static final String PROPERTY_AKAMAI_DOMAIN = "domain";
/** Replication agent action property name. Valid values are "remove" and "invalidate". */
private static final String PROPERTY_AKAMAI_ACTION = "action";
/** Replication agent default type value */
private static final String PROPERTY_AKAMAI_TYPE_DEFAULT = "url";
/** Replication agent default domain value */
private static final String PROPERTY_AKAMAI_DOMAIN_DEFAULT = "production";
/** Replication agent default action value */
private static final String PROPERTY_AKAMAI_ACTION_DEFAULT = "invalidate";
/**Transport URI*/
private static final String TRANSPORT_URI = "transportUri";
/**
* {#inheritDoc}
*/
#Override
public boolean canHandle(AgentConfig config) {
final String transportURI = config.getTransportURI();
return (transportURI != null) && (transportURI.toLowerCase().startsWith(AKAMAI_PROTOCOL));
}
/**
* {#inheritDoc}
*/
#Override
public ReplicationResult deliver(TransportContext ctx, ReplicationTransaction tx)
throws ReplicationException {
final ReplicationActionType replicationType = tx.getAction().getType();
if (replicationType == ReplicationActionType.TEST) {
return ReplicationResult.OK;
} else if (replicationType == ReplicationActionType.ACTIVATE ||
replicationType == ReplicationActionType.DEACTIVATE ||
replicationType == ReplicationActionType.DELETE) {
LOGGER.info("Replication Type in Akamai Handler: {}", replicationType);
String resourcePath = tx.getAction().getPath();
if (StringUtils.startsWith(resourcePath, myProjectConfigurationService.getContentpath())
|| StringUtils.startsWith(resourcePath, myProjectConfigurationService.getAssetpath())) {
// checking for my project specific root page and root dam path.
LOGGER.info("Calling activate in Akamai for path: {}", resourcePath);
try {
return doActivate(ctx, tx);
} catch (RequestSigningException e) {
LOGGER.error("Signing ceremony unsuccessful....");
throw new ReplicationException("Signing ceremony unsuccessful: {}", e);
} catch (IOException e) {
LOGGER.error("IO Exception in deliver \n");
throw new ReplicationException("IO Exception in deliver: {}", e);
}
}
return ReplicationResult.OK;
} else {
throw new ReplicationException("Replication action type " + replicationType + " not supported.");
}
}
private String getTransportURI(TransportContext ctx) throws IOException {
LOGGER.info("Entering getTransportURI method.");
final ValueMap properties = ctx.getConfig().getProperties();
final String AKAMAI_HOST = baseConfigurationService.getPropValueFromConfiguration(AKAMAI_FLUSH_CONFIG_PID, "akamaiHost");
final String domain = PropertiesUtil.toString(properties.get(PROPERTY_AKAMAI_DOMAIN), PROPERTY_AKAMAI_DOMAIN_DEFAULT);
final String action = PropertiesUtil.toString(properties.get(PROPERTY_AKAMAI_ACTION), PROPERTY_AKAMAI_ACTION_DEFAULT);
final String type = PropertiesUtil.toString(properties.get(PROPERTY_AKAMAI_TYPE), PROPERTY_AKAMAI_TYPE_DEFAULT);
String defaultTransportUri = MyConstants.HTTPS + AKAMAI_HOST + "/ccu/v3/"
+ action + MyConstants.BACK_SLASH + type + MyConstants.BACK_SLASH + domain;
String transporturi = PropertiesUtil.toString(properties.get(TRANSPORT_URI), defaultTransportUri);
if(StringUtils.isEmpty(transporturi)) {
return defaultTransportUri;
}
if (transporturi.startsWith(AKAMAI_PROTOCOL)) {
transporturi = transporturi.replace(AKAMAI_PROTOCOL, MyConstants.HTTPS);
}
transporturi = transporturi + "/ccu/v3/"
+ action + MyConstants.BACK_SLASH + type + MyConstants.BACK_SLASH + domain;
LOGGER.info("Exiting getTransportURI method of Akamai Transport Handler : {}", transporturi);
return transporturi;
}
/**
* Send purge request to Akamai via a POST request
*
* Akamai will respond with a 201 HTTP status code if the purge request was
* successfully submitted.
*
* #param ctx Transport Context
* #param tx Replication Transaction
* #return ReplicationResult OK if 201 response from Akamai
* #throws ReplicationException
* #throws RequestSigningException
* #throws IOException
* #throws JSONException
*/
private ReplicationResult doActivate(TransportContext ctx, ReplicationTransaction tx)
throws ReplicationException, RequestSigningException, IOException {
LOGGER.info("Inside doActivate of Akamai");
final String AKAMAI_ACCESS_TOKEN = baseConfigurationService.getPropValueFromConfiguration(AKAMAI_FLUSH_CONFIG_PID, "akamaiAccessToken");
final String AKAMAI_CLIENT_TOKEN = baseConfigurationService.getPropValueFromConfiguration(AKAMAI_FLUSH_CONFIG_PID, "akamaiClientToken");
final String AKAMAI_CLIENT_SECRET = baseConfigurationService.getPropValueFromConfiguration(AKAMAI_FLUSH_CONFIG_PID, "akamaiClientSecret");
final String AKAMAI_HOST = baseConfigurationService.getPropValueFromConfiguration(AKAMAI_FLUSH_CONFIG_PID, "akamaiHost");
ClientCredential clientCredential = ClientCredential.builder().accessToken(AKAMAI_ACCESS_TOKEN).
clientToken(AKAMAI_CLIENT_TOKEN).clientSecret(AKAMAI_CLIENT_SECRET).host(AKAMAI_HOST).build();
HttpTransport httpTransport = new ApacheHttpTransport();
HttpRequestFactory httpRequestFactory = httpTransport.createRequestFactory();
JSONObject jsonObject = createPostBody(ctx, tx);
URI uri = URI.create(getTransportURI(ctx));
HttpRequest request = httpRequestFactory.buildPostRequest(new GenericUrl(uri), ByteArrayContent.fromString("application/json", jsonObject.toString()));
final HttpResponse response = sendRequest(request, ctx, clientCredential);
if (response != null) {
final int statusCode = response.getStatusCode();
LOGGER.info("Response code recieved: {}", statusCode);
if (statusCode == HttpStatus.SC_CREATED) {
return ReplicationResult.OK;
}
}
return new ReplicationResult(false, 0, "Replication failed");
}
/**
* Build preemptive basic authentication headers and send request.
*
* #param request The request to send to Akamai
* #param ctx The TransportContext containing the username and password
* #return JSONObject The HTTP response from Akamai
* #throws ReplicationException if a request could not be sent
* #throws RequestSigningException
*/
private HttpResponse sendRequest(final HttpRequest request, final TransportContext ctx,
ClientCredential clientCredential)
throws ReplicationException, RequestSigningException {
LOGGER.info("Inside Send Request method of Akamai");
final String auth = ctx.getConfig().getTransportUser() + ":" + ctx.getConfig().getTransportPassword();
final String encodedAuth = Base64.encode(auth);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setAuthorization("Basic " + encodedAuth);
httpHeaders.setContentType(ContentType.APPLICATION_JSON.getMimeType());
request.setHeaders(httpHeaders);
GoogleHttpClientEdgeGridRequestSigner requestSigner = new GoogleHttpClientEdgeGridRequestSigner(clientCredential);
requestSigner.sign(request);
HttpResponse response;
try {
response = request.execute();
} catch (IOException e) {
LOGGER.error("IO Exception in sendRequest");
throw new ReplicationException("Could not send replication request.", e);
}
LOGGER.info("Sucessfully executed Send Request for Akamai");
return response;
}
/**
* Build the Akamai purge request body based on the replication agent
* settings and append it to the POST request.
*
* #param request The HTTP POST request to append the request body
* #param ctx TransportContext
* #param tx ReplicationTransaction
* #throws ReplicationException if errors building the request body
*/
private JSONObject createPostBody(final TransportContext ctx,
final ReplicationTransaction tx) throws ReplicationException {
final ValueMap properties = ctx.getConfig().getProperties();
final String type = PropertiesUtil.toString(properties.get(PROPERTY_AKAMAI_TYPE), PROPERTY_AKAMAI_TYPE_DEFAULT);
JSONObject json = new JSONObject();
JSONArray purgeObjects = null;
if (type.equals(PROPERTY_AKAMAI_TYPE_DEFAULT)) {
try {
String content = IOUtils.toString(tx.getContent().getInputStream(), Charset.defaultCharset());
if (StringUtils.isNotBlank(content)) {
LOGGER.info("Content of Akamai is:\n {}", content);
purgeObjects = new JSONArray(content);
}
} catch (JSONException | IOException e) {
throw new ReplicationException("Could not retrieve content from content builder", e);
}
}
if (null != purgeObjects && purgeObjects.length() > 0) {
try {
json.put("objects", purgeObjects);
} catch (JSONException e) {
throw new ReplicationException("Could not build purge request content", e);
}
} else {
throw new ReplicationException("No CP codes or pages to purge");
}
return json;
}
}
Also you would need following dependencies:
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-google-http-client</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client</artifactId>
<version>1.22.0</version>
</dependency>
For my case, the bundle did not resolve and I had to add below dependencies to resolve it. It might differ in your case though:
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-api</artifactId>
<version>0.24.0</version>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-contrib-http-util</artifactId>
<version>0.24.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-context</artifactId>
<version>1.24.0</version>
</dependency>
<Import-Package>
javax.annotation;version=0.0.0,
</Import-Package>
For the line : "IOUtils.toString(tx.getContent().getInputStream(), Charset.defaultCharset());", it internally calls your custom content builder (you can refer the article link I provided earlier). However, you can directly make you content objects in transport handler itself as the transport handler is creating it's own request anyways. However, if you need the session you need to implement the ContentBuilder since TransportHandler implementations do not provide that leverage.
Thanks,
Shubham

Dropwizard, Scribejava, Oauth 2.0 and Github

I'm attempting to authenticate with GitHub via oauth using the scribejava library in a Dropwizard (I guess jetty) application. I'm not overly sure of what I'm doing as I'm new to all this but I've hacked together the following resource class from a number of different blogs and examples.
#Path("/github")
#Produces(MediaType.APPLICATION_JSON)
public class GithubResource {
private static final Logger LOGGER = LoggerFactory.getLogger(GithubResource.class);
public static final String API_KEY = "APIKEY";
public static final String API_SECRET = "SECRETKEY";
private static final String PROTECTED_RESOURCE_URL = "https://api.github.com/users";
private static final Token EMPTY_TOKEN = null;
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response redirectToAuthorization() {
OAuthService service = createService()
.callback("https://localhost:8443/github/continue")
.build();
String authURL = service.getAuthorizationUrl(EMPTY_TOKEN);
return Response.seeOther(URI.create(authURL)).build();
}
#GET
#Path("continue")
#Produces(MediaType.TEXT_PLAIN)
public Response redirectToApp(#QueryParam("client_id") String oauthToken, #QueryParam("code") String oauthVerifier) {
OAuthService service = createService().build();
Verifier verifier = new Verifier(oauthVerifier);
Token requestToken = service.getAccessToken(EMPTY_TOKEN, verifier);
Token accessToken = service.getAccessToken(requestToken, verifier);
OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL, service);
service.signRequest(accessToken, request);
com.github.scribejava.core.model.Response response = request.send();
return Response.ok(response.getBody()).build();
}
private ServiceBuilder createService() {
return new ServiceBuilder()
.provider(GitHubApi.class)
.apiKey(API_KEY)
.apiSecret(API_SECRET);
}
}
It's taken me a few days to get to this point but I can now successfully pull out the code from the response from github (I think) but then the app crashes with the following error log
ERROR [2015-11-23 03:12:37,417] io.dropwizard.jersey.errors.LoggingExceptionMapper: Error handling a request: fdf48e68be65c626
! com.github.scribejava.core.exceptions.OAuthException: Response body is incorrect. Can't extract a token from this: 'error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdeveloper.github.com%2Fv3%2Foauth%2F%23redirect-uri-mismatch2'
! at com.github.scribejava.core.extractors.TokenExtractor20Impl.extract(TokenExtractor20Impl.java:32) ~[scribejava-core-2.0.jar:na]
! at com.github.scribejava.core.oauth.OAuth20ServiceImpl.getAccessToken(OAuth20ServiceImpl.java:37) ~[scribejava-core-2.0.jar:na]
! at org.squandered.generator.resource.GithubResource.redirectToApp(GithubResource.java:58) ~[classes/:na]
! at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_51]
! at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_51]
! at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_51]
! at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_51]
I see the "Response body is incorrect. Can't extract a token from this" but I'm really not sure how I can correctly do this...
Does anyone see any obvious flaws with my code, or have a working example of using these libraries with oauth 2.0? Google seems to return results for oauth 1.0 which is a little different...
Appreciate any help in the right direction
Cheers
Was actually a very simple bug, I wasn't pulling the correct param from the response URL in the callback method. Complete working example:
import com.github.scribejava.apis.GitHubApi;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.model.OAuthRequest;
import com.github.scribejava.core.model.Token;
import com.github.scribejava.core.model.Verb;
import com.github.scribejava.core.model.Verifier;
import com.github.scribejava.core.oauth.OAuthService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
import java.util.Random;
#Path("/github")
public class GithubResource {
private static final Logger LOGGER = LoggerFactory.getLogger(GithubResource.class);
private static final String PROTECTED_RESOURCE_URL = "https://api.github.com/user";
private static final String API_KEY = "your key";
private static final String API_SECRET = "your secret";
private static final String CALL_BACK_URL = "https://localhost:8443/github/callback/";
private static final Token EMPTY_TOKEN = null;
#GET
public Response getToken() {
OAuthService service = createService().build();
final String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN);
return Response.seeOther(URI.create(authorizationUrl)).build();
}
#GET
#Path("callback")
#Produces(MediaType.TEXT_PLAIN)
public Response callback(#QueryParam("code") String oauthToken) {
OAuthService service = createService().build();
final Verifier verifier = new Verifier(oauthToken);
final Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier);
final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL, service);
service.signRequest(accessToken, request);
final com.github.scribejava.core.model.Response response = request.send();
LOGGER.info("Response code: " + response.getCode());
LOGGER.info("Response body: " + response.getBody());
return Response.ok(response.getBody()).build();
}
private ServiceBuilder createService() {
return new ServiceBuilder()
.provider(GitHubApi.class)
.apiKey(API_KEY)
.apiSecret(API_SECRET)
.scope("repo")
.state("secret" + new Random().nextInt(999_999))
.callback(CALL_BACK_URL);
}
}

How to POST request to Google Shortener API with Google API Java Client and parse a JSON response?

I want to use the Google Shortener API. I want to use the google api java client library to post a request and parse the JSON response.
Next, I post the code I have tried:
import java.io.IOException;
import net.sf.json.JSONObject;
import com.google.api.client.googleapis.GoogleHeaders;
import com.google.api.client.googleapis.GoogleTransport;
import com.google.api.client.googleapis.json.JsonCParser;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonHttpContent;
import com.google.api.client.util.GenericData;
public class GoogleShortener {
public static final String GOOGL_URL = "https://www.googleapis.com/urlshortener/v1/url";
public static void main(String[] args) {
// setup up the HTTP transport
HttpTransport transport = GoogleTransport.create();
// add default headers
GoogleHeaders defaultHeaders = new GoogleHeaders();
transport.defaultHeaders = defaultHeaders;
transport.defaultHeaders.put("Content-Type", "application/json");
transport.addParser(new JsonCParser());
// build the HTTP GET request and URL
GenericData data = new GenericData();
data.put("longUrl", "http://www.google.com/");
JsonHttpContent content = new JsonHttpContent();
content.data = data;
HttpRequest request = transport.buildPostRequest();
request.content = content;
request.setUrl(GOOGL_URL);
HttpResponse response;
try {
JSONObject json = request.execute().parseAs(JSONObject.class);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
When I execute the above code, I get the next output:
Exception in thread "main" java.lang.IllegalArgumentException: data key not found
at com.google.api.client.googleapis.json.JsonCParser.parserForResponse(JsonCParser.java:77)
at com.google.api.client.googleapis.json.JsonCParser.parse(JsonCParser.java:47)
at com.google.api.client.http.HttpResponse.parseAs(HttpResponse.java:261)
at GoogleShortener.main(GoogleShortener.java:43)
Any idea how to set the JsonCParser properly?
ERROR PATH
In the beginning I was not setting properly the request content. As pointed by #dwb, the request content should be set:
GenericData data = new GenericData();
data.put("longUrl", "http://www.google.com/");
JsonHttpContent content = new JsonHttpContent();
content.data = data;
request.content = content;
If you do not set the content properly, you will get the next error
com.google.api.client.http.HttpResponseException:
411 Length Required at
com.google.api.client.http.HttpRequest.execute(HttpRequest.java:209)
at
GoogleShortener.main(GoogleShortener.java:32)
You need to add JSON content to the request body like this:
GenericData data = new GenericData();
data.put("longUrl", "http://www.google.com/");
JsonHttpContent content = new JsonHttpContent();
content.data = data;
request.content = content;
For the response, try using the JsonHttpParser instead of JsonCParser. You'll need to create a subclass of GenericJson that contains fields with a #Key annotation for every JSON property you want to retrieve. You can use response.parseAsString() to see all of the properties available.
Here's a full working example:
import com.google.api.client.googleapis.GoogleHeaders;
import com.google.api.client.googleapis.GoogleTransport;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonHttpContent;
import com.google.api.client.json.JsonHttpParser;
import com.google.api.client.util.GenericData;
import com.google.api.client.util.Key;
public class Shortener {
public static final String GOOGL_URL = "https://www.googleapis.com/urlshortener/v1/url";
/**
* #param args
*/
public static void main(String[] args) throws Exception {
// setup up the HTTP transport
HttpTransport transport = GoogleTransport.create();
// add default headers
GoogleHeaders defaultHeaders = new GoogleHeaders();
transport.defaultHeaders = defaultHeaders;
transport.defaultHeaders.put("Content-Type", "application/json");
transport.addParser(new JsonHttpParser());
// build the HTTP GET request and URL
HttpRequest request = transport.buildPostRequest();
request.setUrl(GOOGL_URL);
GenericData data = new GenericData();
data.put("longUrl", "http://www.google.com/");
JsonHttpContent content = new JsonHttpContent();
content.data = data;
request.content = content;
HttpResponse response = request.execute();
Result result = response.parseAs(Result.class);
System.out.println(result.shortUrl);
}
public static class Result extends GenericJson {
#Key("id")
public String shortUrl;
}
}
The code given by dwb is correct but it is using deprecated methods of the google client api.
Implementation with current library support is as follows :
import java.util.HashMap;
import java.util.Map;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpContent;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.json.JsonHttpContent;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonObjectParser;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.client.util.Key;
public class ShortenUrl {
/**
* #param args
*/
public static void main(String[] args) throws Exception {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
HttpHeaders headers = new HttpHeaders();
JsonObjectParser parser = new JsonObjectParser(new JacksonFactory());
GenericUrl url = new GenericUrl("https://www.googleapis.com/urlshortener/v1/url");
Map<String, String> json = new HashMap<String, String>();
json.put("longUrl", "http://www.google.com/");
final HttpContent content = new JsonHttpContent(new JacksonFactory(), json);
HttpRequest request = httpTransport.createRequestFactory().buildPostRequest(url, content);
try {
HttpResponse response = request.execute();
Result result = response.parseAs(Result.class);
System.out.println(result.shortUrl);
} catch (Exception e) {
e.printStackTrace();
}
}
public static class Result extends GenericJson {
#Key("id")
public String shortUrl;
}
}
Note : You should use your Oauth 2.0 credentials to use google api services.

Categories