Dropwizard, Scribejava, Oauth 2.0 and Github - java

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);
}
}

Related

How to call another rest api from my controller in Micronaut

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.

Keycloak - How to refresh token witj Java client?

I'm looking for refresh token by using the Java Admin Client https://github.com/keycloak/keycloak/tree/master/integration/admin-client
Cannot find anything about it
Regards
EDIT :
finally I go that :
public AccessTokenResponse executeRefresh(String refreshToken) {
String url = "https://url/auth" + "/realms/" + keycloakRealm + "/protocol/openid-connect/token";
Configuration kcConfig = new Configuration(authServerUrl, keycloakRealm, keycloakInternalClientId, null, null);
Http http = new Http(kcConfig, (params, headers) -> {
});
return http.<AccessTokenResponse>post(url)
.authentication()
.client()
.form()
.param("grant_type", "refresh_token")
.param("refresh_token", refreshToken)
.param("client_id", keycloakInternalClientId)
.param("client_secret", keycloakInternalClientSecret)
.response()
.json(AccessTokenResponse.class)
.execute();
}
org.keycloak.admin.client.Keycloak.tokenManager().refreshToken() can refresh token. For example:
// Create a Keycloak client
Keycloak kc = KeycloakBuilder.builder()
.serverUrl("http://localhost:8080/auth")
.realm("master")
.username("admin")
.password("password")
.clientId("admin-cli")
.resteasyClient(new ResteasyClientBuilder().connectionPoolSize(10).build())
.build();
TokenManager tokenManager = kc.tokenManager();
// get access token
AccessTokenResponse accessTokenResponse = tokenManager.getAccessToken();
System.out.println(accessTokenResponse.getRefreshToken());
// Refresh token
accessTokenResponse = tokenManager.refreshToken();
System.out.println(accessTokenResponse.getRefreshToken());
Sadly Java Admin Client does not have this kind of functionality (hopefully will have in the future)
For now, look at this answer:
Refresh access_token via refresh_token in Keycloak
Have achieved it through RestTemplate inside my spring-boot application.
Below is the code I have used to get refresh token :-
public ResponseEntity<RefreshTokenResponse> refreshToken(String refreshToken) {
String url = authUrl+ "/realms/" + realm + "/protocol/openid-connect/token";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("grant_type", "refresh_token");
map.add("refresh_token", refreshToken);
map.add("client_id", clientId);
map.add("client_secret", clientSecret);
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);
ResponseEntity response =
restTemplate.exchange(url,
HttpMethod.POST,
entity,
Object.class);
return response;}
RefreshTokenResponse :-
#Data
public class RefreshTokenResponse {
private AccessTokenResponse token;
}
Keycloak v19.0.0
authUrl :- where keycloak server is running. my case
http://localhost:8080/
ream :- your realm name
Actually, I managed to make Keycloak client do this job for me after spending some time with the issue. In my case I had to connect to a Keycloak server with password grant type, and use access token to fetch data from a third party protected endpoint in a Spring Boot server side application.
At the end I came up with a service, which provides an access token after initial authentication, and automatic refresh/re-authentication on demand.
I added a #Configuration bean, which contained the connection parameters to the third party Keycloak instance:
package no.currentclient.application.api.config; // real package name masked
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class OauthClientConfig {
public record OauthConfig(String realm, String authServerUrl, String clientId, String username, String password) {
}
#Bean
OauthConfig oauthConfig(
#Value("${client.oauth.realm}") String realm,
#Value("${client.oauth.auth-server-url}") String authServerUrl,
#Value("${client.oauth.resource}") String clientId,
#Value("${client.oauth.username}") String username,
#Value("${client.oauth.password}") String password
) {
return new OauthConfig(realm,
authServerUrl,
clientId,
username,
password);
}
}
After I created a Spring Service which is capable of authenticating, getting and refreshing an access token:
package no.currentclient.application.auth.oauthclient; // real package name masked
import com.fasterxml.jackson.databind.ObjectMapper;
import no.currentclient.application.api.config.OauthClientConfig;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.keycloak.authorization.client.representation.ServerConfiguration;
import org.keycloak.authorization.client.util.Http;
import org.keycloak.authorization.client.util.TokenCallable;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Collections;
#Service
public class OauthTokenService {
private final TokenCallable tokenCallable;
public OauthTokenService(
OauthClientConfig.OauthConfig oauthConfig,
OkHttpClient okHttpClient
) throws IOException {
var serverConfiguration = getServerConfiguration(oauthConfig.authServerUrl()+"/auth/realms/"+oauthConfig.realm()+"/.well-known/openid-configuration", okHttpClient);
var config = new org.keycloak.authorization.client.Configuration(
// These might all be set to null -> only tokenMinimumTimeToLive is used in TokenCallable...
null,null,null, null,null);
var http = new Http(config, (requestParams, requestHeaders) -> requestParams.put("client_id", Collections.singletonList("deichman")));
tokenCallable = new TokenCallable(oauthConfig.username(), oauthConfig.password(), http, config, serverConfiguration);
}
/*
* Call this method to get hold of an on-demand refreshed auth token. TokenCallable handles the burden of token
* refresh and re-authentication in case of session timeout.
*/
public String getAccessToken() {
return tokenCallable.call();
}
private ServerConfiguration getServerConfiguration(String configUrl, OkHttpClient okHttpClient) throws IOException {
var configRequest = new Request.Builder().url(configUrl).get().build();
try (var response = okHttpClient.newCall(configRequest).execute()) {
return new ObjectMapper().readValue(response.body().string(), ServerConfiguration.class);
}
}
}
TokenCallable hides all the complexity of refresh/re-authentication on demand.
Hope it helps a few struggling with this problem.

Aweber Java Api

My goal is to create an aweber app that adds users to an email list I already have.
I currently have code that uses Oauth to get a token but this method also requires an aweber account users
to manually write their credentials in order to grant the app access. I would only ever be using my aweber 'app'
for my own purposes and I want to automate the process of authentication. Look for the comment "//going to the url manually here".
Thanks in advance for the help.
package aweber.test;
import java.util.Scanner;
import org.scribe.builder.ServiceBuilder;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
impo rt org.scribe.model.Verb;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;
public class AweberStuffTest
{
//To get your consumer key/secret, and view API docs, see https://labs.aweber.com/docs
private static final String ACCOUNT_RESOURCE_URL = "https://api.aweber.com/1.0/accounts/";
private static final String CONSUMER_KEY = "AkW******8QO0dMmmF";
private static final String CONSUMER_SECRET = "zfgmPsZkXBam6R***********YD";
public static void main(String[] args)
{
OAuthService service = new ServiceBuilder()
.provider(AWeberApi.class)
.apiKey(CONSUMER_KEY)
.apiSecret(CONSUMER_SECRET)
.build();
Scanner in = new Scanner(System.in);
System.out.println("=== AWeber's OAuth Workflow ===");
System.out.println();
// Obtain the Request Token
System.out.println("Fetching the Request Token...");
Token requestToken = service.getRequestToken();
System.out.println("Got the Request Token!");
System.out.println();
System.out.println("Now go and authorize Scribe here:");
String foo = service.getAuthorizationUrl(requestToken);
System.out.println(foo);
//going to the url manually here
System.out.println("And paste the verifier here");
System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine());
System.out.println();
// Trade the Request Token and Verfier for the Access Token
System.out.println("Trading the Request Token for an Access Token...");
Token accessToken = service.getAccessToken(requestToken, verifier);
System.out.println("Got the Access Token!");
System.out.println("(if your curious it looks like this: " + accessToken + " )");
System.out.println();
// Now let's go and ask for a protected resource!
System.out.println("Now we're going to access a protected resource...");
OAuthRequest request = new OAuthRequest(Verb.GET, ACCOUNT_RESOURCE_URL);
service.signRequest(accessToken, request);
Response response = request.send();
System.out.println("Got it! Lets see what we found...");
System.out.println();
System.out.println(response.getBody());
System.out.println();
System.out.println("Thats it man! Go and build something awesome with AWeber and Scribe! :)");
}
}
and
package aweber.test;
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;
public class AWeberApi extends DefaultApi10a
{
private static final String AUTHORIZE_URL = "https://auth.aweber.com/1.0/oauth/authorize?oauth_token=%s";
private static final String REQUEST_TOKEN_ENDPOINT = "https://auth.aweber.com/1.0/oauth/request_token";
private static final String ACCESS_TOKEN_ENDPOINT = "https://auth.aweber.com/1.0/oauth/access_token";
#Override
public String getAccessTokenEndpoint()
{
return ACCESS_TOKEN_ENDPOINT;
}
#Override
public String getRequestTokenEndpoint()
{
return REQUEST_TOKEN_ENDPOINT;
}
#Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZE_URL, requestToken.getToken());
}
}

Spring security with google Oauth

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

How to create a oAuth request using java?

I need to make a connection with Viagogo website using oAuth. Referring to their documentation I need to create a request similar to the following one
Using the example in step 1A, this means you may generate a signature base string that looks like the following:
GET&http%3A%2F%2Fapi.viagogo.net%2FPublic%2FSimpleOAuthAccessRequest&oauth_consumer_key%3Dtestkey%26oauth_nonce%3Dmyn0nc3%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1292404912%26oauth_version%3D1.0%26scope%3DAPI.Public
I am using the following code but when I comment lines 1,2 it return unauthorized error, and when I use them it shows oauthService.signRequest returns void.
TradeKingAPI.java
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;
public class TradeKingAPI extends DefaultApi10a {
#Override
public String getRequestTokenEndpoint() {
return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
}
#Override
public String getAccessTokenEndpoint() {
return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
}
#Override
public String getAuthorizationUrl(Token requestToken) {
return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
}
}
main.java
import org.scribe.builder.ServiceBuilder;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.oauth.OAuthService;
import api.TradeKingAPI;
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.OAuthConstants;
import org.scribe.oauth.OAuthService;
........
OAuthService oauthService = new ServiceBuilder()
.provider(TradeKingAPI.class)
.apiKey("My consumer key")
.apiSecret("My secret")
.scope("API.Public")
.build();
Long seconds = (System.currentTimeMillis() / 1000);
System.out.println(">>>" + seconds);
String stSeconds = seconds.toString();
OAuthRequest request = new OAuthRequest(Verb.GET, "http://api.viagogo.net/Public
/SimpleOAuthAccessRequest");
request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, "My consumer key");
request.addOAuthParameter(OAuthConstants.NONCE, "myn0nc3");
request.addOAuthParameter(OAuthConstants.SIGN_METHOD, "HMAC-SHA1");
request.addOAuthParameter(OAuthConstants.TIMESTAMP, seconds.toString());
request.addOAuthParameter(OAuthConstants.VERSION, "1.0");
request.addOAuthParameter("scope", "API.Public");
1 String signature = oauthService.signRequest(OAuthConstants.EMPTY_TOKEN, request);
2 request.addOAuthParameter(OAuthConstants.SIGNATURE,signature);
Response response = request.send();
System.err.println(">>" + response.isSuccessful());
System.err.println(">>" + response.getMessage());
System.err.println(">>" + response.getBody());
From what I understand from Viagogo public API access documentation, the token you get in the step 1, is the equivalent to a request token in a complete OAuth 1.0a "dance".
So, you should be able to use scribe-java internal classes to get this token without doing it by hand. The only difference is that in scribe, this request sends also a callback url to the OAuth server for the next step of OAuth "dance".
As I can't get a consumer account I can only make assumption here. So let's have 2 scenarios :
Scenario 1 : Viagogo server tolerate extra parameter (i.e. call back URL)
so you can go with this code
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;
public class TradeKingAPI extends DefaultApi10a {
#Override
public Verb getRequestTokenVerb()
{
return Verb.GET;
}
#Override
public String getRequestTokenEndpoint() {
return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
}
#Override
public String getAccessTokenEndpoint() {
return "none";
}
#Override
public String getAuthorizationUrl(Token requestToken) {
return "none";
}
}
Then your calling code will be :
OAuthService service = new ServiceBuilder()
.provider(TradeKingAPI.class)
.signatureType(QueryString)
.apiKey("My consumer key")
.apiSecret("My secret")
.scope("API.Public")
.build();
Token requestToken = service.getRequestToken();
//make your API calls
OAuthRequest request = new OAuthRequest(Verb.GET,
"http://api.viagogo.net/Public/Event/235");
service.signRequest(requestToken, request);
Response response = request.send();
System.out.println(response.getBody());
But as I said, if Viagogo security is a bit strict and it refuses the useless param oauth_callback, you'll need to switch to scenario 2
Scenario 2 : Build your own OAuthService
In this scenario you have to create a new OAuthService to avoid dealing with OAuthCallback parameter.
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.*;
import org.scribe.oauth.OAuth10aServiceImpl;
import java.util.Map;
public class OAuth10aServiceForViagogo extends OAuth10aServiceImpl {
private OAuthConfig config;
private DefaultApi10a api;
public OAuth10aServiceForViagogo(DefaultApi10a api, OAuthConfig config) {
super(api, config);
this.api = api;
this.config = config;
}
private void addOAuthParams(OAuthRequest request, Token token) {
request.addOAuthParameter(OAuthConstants.TIMESTAMP, api.getTimestampService().getTimestampInSeconds());
request.addOAuthParameter(OAuthConstants.NONCE, api.getTimestampService().getNonce());
request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey());
request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService().getSignatureMethod());
request.addOAuthParameter(OAuthConstants.VERSION, getVersion());
request.addOAuthParameter(OAuthConstants.SCOPE, config.getScope());
request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token));
}
private String getSignature(OAuthRequest request, Token token) {
String baseString = api.getBaseStringExtractor().extract(request);
String signature = api.getSignatureService().getSignature(baseString, config.getApiSecret(), token.getSecret());
return signature;
}
private void appendSignature(OAuthRequest request) {
for (Map.Entry<String, String> entry : request.getOauthParameters().entrySet()) {
request.addQuerystringParameter(entry.getKey(), entry.getValue());
}
}
#Override
public Token getRequestToken(RequestTuner tuner) {
OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint());
addOAuthParams(request, OAuthConstants.EMPTY_TOKEN);
appendSignature(request);
Response response = request.send(tuner);
String body = response.getBody();
return api.getRequestTokenExtractor().extract(body);
}
}
TrakingApi class will be slightly different to create the an OAuth10aServiceForViagogo when calling createService :
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;
public class TradeKingAPI extends DefaultApi10a {
#override
public OAuthService createService(OAuthConfig config)
{
return new OAuth10aServiceForViagogo(this, config);
}
#Override
public Verb getRequestTokenVerb()
{
return Verb.GET;
}
#Override
public String getRequestTokenEndpoint() {
return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
}
#Override
public String getAccessTokenEndpoint() {
return "none";
}
#Override
public String getAuthorizationUrl(Token requestToken) {
return "none";
}
}
Then your calling code will be the same :
OAuthService service = new ServiceBuilder()
.provider(TradeKingAPI.class)
.signatureType(QueryString)
.apiKey("My consumer key")
.apiSecret("My secret")
.scope("API.Public")
.build();
Token requestToken = service.getRequestToken();
//make your API calls
OAuthRequest request = new OAuthRequest(Verb.GET,
"http://api.viagogo.net/Public/Event/235");
service.signRequest(requestToken, request);
Response response = request.send();
System.out.println(response.getBody());
I didn't test all this code because I can't access consumer and secret key, but it should be close to what you need.
I'm assuming you're trying to get the access token (e.g you're calling SimpleOAuthAccessRequest). Scribe's OauthService has methods to handle this.
BUT ... if you're going to do it manually, here is what's wrong with your code - at least with what you've listed here. I'm assuming you've configured scribe correctly.
don't pass the consumer secret with your request, that is only for signing the request
you should use addOauthParameter vs addQueryStringParameter
you should use the Scribe constants
you need to sign the request (again, Scribe's OauthService has help method for signing request)
Here's your updated snippet of code.
UPDATE:
Have Scribe provide all the Oauth parameters for you
OAuthRequest request = new OAuthRequest(Verb.GET, ...
//since you're just passing Oauth parameters and nothing else,
//you can use signRequest will create Oauth Parameters for you
service.signRequest(OAuthConstants.EMPTY_TOKEN, request)
Response response = request.send()

Categories