I'm trying to validate an OpenSocial 0.7 signed request, using the sample Java code on that page. I think it should work this way, but I still get a signature_invalid error.
Main validation code:
// NOTE: req = HttpServletRequest
// check for hyves
if (!"hyves.nl".equals(req.getParameter("oauth_consumer_key"))) {
throw new RuntimeException("Only hyves supported");
}
// update hyves' certificate
getHyvesCert(req.getParameter("xoauth_signature_publickey"));
// construct message object
OAuthMessage oaMessage = new OAuthMessage(req.getMethod(), getRequestUrl(req), getParameters(req));
// validate message
// (will throw exception if invalid)
new SimpleOAuthValidator().validateMessage(oaMessage, new OAuthAccessor(OAUTH_CONSUMER_HYVES));
OAUTH_CONSUMER_HYVES:
private static final OAuthServiceProvider OAUTH_THIS = new OAuthServiceProvider(null, null, null);
private static final OAuthConsumer OAUTH_CONSUMER_HYVES = new OAuthConsumer(null, "hyves.nl", null, OAUTH_THIS);
getHyvesCert:
public void getHyvesCert(String name) {
synchronized(certLoadLock) {
// in reality this is code that downloads the certificate
// with the specified name, but this is the result
hyvesCert = "---BEGIN CERTIFICATE---- etc...";
OAUTH_CONSUMER_HYVES.setProperty(RSA_SHA1.X509_CERTIFICATE, hyvesCert);
}
}
The methods getRequestUrl and getParameters are directly copied from here.
I found the problem. getRequestUrl() returned the wrong URL because Tomcat is behind an nginx proxy. So while the sender would use the URL "http://example.com/bla" to sign the request, the server was using "http://example.com:8080/bla" to validate it.
Related
I'm not sure what I've done wrong. But the requestSigner.isMatch always returns invalid request.
I've used this https://github.com/messagebird/java-rest-api/blob/master/examples/src/main/java/ExampleRequestSignatureValidation.java as my reference but still same :(
public boolean isValidRequest(String signingKey, String timestamp, InputStream requestBody) throws IOException {
RequestSigner requestSigner = new RequestSigner(messageBirdSigningKey.getBytes());
byte[] bodyBytes = readAllBytes(requestBody);
Request request = new Request(timestamp, "", bodyBytes);
return requestSigner.isMatch(signingKey, request);
}
I pass an empty string for the queryParams since the incoming message has null queryParams.
The messageBirdSigningKey is the signing key provided by message bird.
Any leads would be a great help!
thank you!
Have been struggling for last few days with this error Authentication of type {http://service.soap.xcompany.com}AuthenticationHeader had undefined attribute {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id while invoking a service call from a C# WCF client (targeting .Net 4.5 framework) to a Java Soap Service hosted externally with end-to-end encryption (both client and service certificates are used). When I tested the service using SoapUI with a JKS file, request was processed successfully.
So to see what's difference between the two requests, I did the followings:
Used Fiddler Inspector to capture two requests, one from SoapUI which was successful and one from C# which failed with 500 error
Extracted these two Xml messages into two C# classes (named them RequestByJava and RequestByDotNet, respectively) using the VS2017 feature Edit/Paste Special/Paste Xml as Classes.
Use XmlSerializer to de-serialize the two requests into the two objects of the types created in 2) and compared their properties.
With the Soap error message in mind, I narrowed down the difference between two Authentication headers - interestingly there is one extra property "Id" in the RequestByDotNet object whereas the RequestByJava object does not have. And the 500 Soap error message seemed to indicate that there was a schema validation error due to that undefined element "Id"
Also noticed that the RequestByDotNet.Header.Security.BinarySecurityToken.ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" but RequestByJava (SoapUI) has a different ValueType "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1"
Another difference, not sure it matters, is that the Request from .net codes has a "mustunderstand" value under the Header.Security set to true while the one from Java does not.
My questions are:
Why is the difference?
How can this be fixed without having to write a Java client?
Some codes used binding and endpoint behavior:
private static CustomBinding BuildCustomBinding()
{
var binding = new CustomBinding();
var textMessageEncoding = new TextMessageEncodingBindingElement()
{
MessageVersion = MessageVersion.Soap11
};
var securityBindingElement =
SecurityBindingElement.CreateMutualCertificateBindingElement(
MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, true);
binding.Elements.AddRange(textMessageEncoding, securityBindingElement, new HttpsTransportBindingElement());
return binding;
}
private static void CallAccountService()
{
//credential for test
const string applId = "testuser";
const string pwd = "password";
//for client certificate, import client.pfx to LocalMachine's Trusted Root Certification Authorities and make sure the thumbprint matches
var client = new NOLWSAccountSvc.WSAccountv1Client(BuildCustomBinding(), GetAccountServiceEndpointAddress());
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.Root, X509FindType.FindByThumbprint, "thumbprintvalue");
//for service certificate, import service-provider.cer to same store location and store name and make sure the thumbprint matches
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.Root,
X509FindType.FindByThumbprint, "thumprintvalue");
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;
client.Open();
var header = new NOLWSAccountSvc.AuthenticationHeader()
{
application_id = applId,
password = pwd
};
var getActiveAccountsFunc = new NOLWSAccountSvc.getActiveAccounts() { applRef = "softact-dev", resetRows = true };
try
{
var response = client.getActiveAccounts(header, getActiveAccountsFunc);
Console.WriteLine(response.moreData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
}
Thanks for your time! Your help will be highly appreciated.
#jdweng Yes, I did; here were two request bodies, first from .Net and 2nd from SoapUI:
.Net Request:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><h:Authentication u:Id="_2" xmlns:h="http://service.soap.xcompany.com" xmlns="http://service.soap.xcompany.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><application_id>testuserid</application_id><password>testpassword</password></h:Authentication><ActivityId CorrelationId="d7085e6f-b757-46e8-b3eb-319a51d568a3" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">00000000-0000-0000-0000-000000000000</ActivityId><VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo8DAzaQVkApDpl1Tc1YTHQwAAAAAMbeMEvBLCUqoD7kEDPHDKYukgggNOf5FtHBB/Sa7ggkACQAA</VsDebuggerCausalityData><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:BinarySecurityToken u:Id="uuid-eb310312-396a-4d00-8922-f77de97138cb-3" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">MIIDYzCCAkugAwIBAgIEaGKzJDANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJ1czEPMA0GA1UEChMGU3ByaW50MREwDwYDVQQLEwhQcm9qZWN0czEMMAoGA1UECxMDQk1QMQwwCgYDVQQLEwNUUEExEzARBgNV</o:BinarySecurityToken><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#_1"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>WCpRwVjx89ceVctR8lp9LNGKHeA=</DigestValue></Reference><Reference URI="#_2"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>8/PErh8BL9To5zazpP9CbPFTAa8=</DigestValue></Reference></SignedInfo><SignatureValue>hOtpz7lXvZPPbBD6sV1hxyx3Hc39vj0q2GYKMd8oQbgTbbuKC7QKcZOjktqUxayrzc6h/V0j7Kx3APPONe4F3A2581nK4AQ72yYonsaeXQW0yzSxW/VTsN04uoqCP6IpKXqlAz40VeWGUPJOeGthCKy/9A+NSuqS</SignatureValue><KeyInfo><o:SecurityTokenReference><o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-eb310312-396a-4d00-8922-f77de97138cb-3"/></o:SecurityTokenReference></KeyInfo></Signature></o:Security></s:Header><s:Body u:Id="_1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><getActiveAccounts xmlns="http://service.soap.xcompany.com"><applRef>dev</applRef><resetRows>false</resetRows></getActiveAccounts></s:Body></s:Envelope>
SoapUI Request:
(somehow it won't let me past whole xml here.. )
Well, my colleague helped me figure out way to remove the extra headers from the request before it was posted to the Java SOAP service endpoint - the key was to use IClientMessageInspector and implement some logic in the BeforeSendRequest to remove the unwanted headers that were rejected by the service provider; then add a custom FormattingBehavior class to inherit from IEndpointBheavior and in the IEndPointBehavior.ApplyClientBehavior, attach the MyClientMessageInspector; finally add the customer endpoint behavior to the web service client. Here are the codes:
Where and how to remove unwanted request headers:
public class MyClientMessageInspector : IClientMessageInspector
{
public MyClientMessageInspector(ServiceEndpoint endpoint)
{
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
//Console.WriteLine(request.ToString());
var lstUnwantedStuff = new[]
{
new KeyValuePair<string, string>("Action", "http://www.w3.org/2005/08/addressing"),
new KeyValuePair<string, string>("VsDebuggerCausalityData",
"http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink")
};
foreach (var kv in lstUnwantedStuff)
{
var indexOfUnwantedHeader = request.Headers.FindHeader(kv.Key, kv.Value);
if (indexOfUnwantedHeader>=0)
{
request.Headers.RemoveAt(indexOfUnwantedHeader);
}
}
...
Where and how to use the custom ClientMessageInspector:
internal class MyFaultFormatterBehavior : IEndpointBehavior
{
...
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyClientMessageInspector(endpoint));
}
}
Where and how to attach custom EndpointBehavior:
private static void CallAccountService()
{
var client = new WSAccountv1Client(BuildCustomBinding(), GetAccountServiceEndpointAddress());
//Set client certificate
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.Root, X509FindType.FindByThumbprint, "xxxxxxxxxx");
//for service certificate
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople,
X509FindType.FindByThumbprint, "xxxxxxxxxxxxxxxxy");
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;
//add faultformattingbehavior so we can intercept the fault reply message
client.Endpoint.EndpointBehaviors.Add(new MyFaultFormatterBehavior());
client.Open();
var header = new AuthenticationHeader()
{
application_id = applId,
password = pwd
};
var getActiveAccountsFunc = new getActiveAccounts() { applRef = "test", resetRows = true };
try
{
//MyClientMessageInspector.BeforeSendRequest is entered when this called is made
var response = client.getActiveAccounts(header, getActiveAccountsFunc);
Console.WriteLine(response.moreData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
}
What else?
In the proxy classes, need to set the Authentication ProtectionLevel to None while on the Service level it needs to be set as ProtectionLevel.Sign:
Request level:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(IsWrapped = false)]
public partial class getActiveAccountsRequest
{
[System.ServiceModel.MessageHeaderAttribute(Namespace = "http://service.xcompany.com"
, ProtectionLevel = System.Net.Security.ProtectionLevel.None
)]
public AuthenticationHeader Authentication;
Service (Interface) Level:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace = "http://service.xcompany.com",
ConfigurationName = "WSAccount"
, ProtectionLevel = ProtectionLevel.Sign
)]
public interface WSAccount
{
I was trying to build a RESTful web service using Jersey.
In my server side code, there is a path with name "domain" which I use to display content. The content of the page the "domain" refers to is accessible only correct username and password are input.
#POST
#Produces(MediaType.APPLICATION_JSON)
#Path("domain")
public ArrayList<String> domainList(#Context HttpServletRequest req) throws Exception{
Environments environments = new DefaultConfigurationBuilder().build();
final ALMProfile profile = new ALMProfile();
profile.setUrl(environments.getAutomation().getAlmProfile().getUrl());
profile.setUsername((String) req.getSession().getAttribute("username"));
//Set username from input, HTML form
profile.setPassword((String) req.getSession().getAttribute("password"));
//Set password from input, HTML form
try (ALMConnection connection = new ALMConnection(profile);) {
if (connection.getOtaConnector().connected()) {
Multimap<String, String> domain = connection.getDomains();
ArrayList<String> domain_names = new ArrayList<String>();
for(String key : domain.keys()){
if(domain_names.contains(key)) domain_names.add(key);
}
return domain_names; //return the content
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return null;
}
When I attempted to test if correct content was returned, I got an error (status=405, reason=Method Not Allowed). Below is my client side test.
public static void main(String[] args){
Environments environments = new DefaultConfigurationBuilder().build();
final ALMProfile profile = new ALMProfile();
profile.setUrl(environments.getAutomation().getAlmProfile().getUrl());
profile.setUsername("username"); //Creating a profile with username and password
profile.setPassword("password");
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target(getBaseURI());
String response = target.path("domain").request().accept
(MediaType.APPLICATION_JSON).get(Response.class).toString();
//Above is the GET method I see from an example,
//probably is the reason why 405 error comes from.
System.out.println(response);
}
private static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost:8080/qa-automation-console").build();
}
The servlet configuration is good. We have other paths succesfully running.
I suspect the reason might come from I used a GET method to do the job that is supposed to be POST.
But I am not familiar to Jersey methods I can use.
Does anyone know any methods that I can use to test the functionality?
See 405 Status Code
405 Method Not Allowed
The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. The response MUST include an Allow header containing a list of valid methods for the requested resource.
Your endpoint is for a #POST request. In your client you are trying to get().
See the Client API documentation for information on how to make a POST request. If it is supposed to be a GET request, then simply change the method annotation to #GET.
Also note, for your #POST resource methods, you should always put a #Consumes annotation with the media types the method supports. If the client send a media type not supported, then they will get a 415 not supported as expected. I would have posted an example of the client post, but I have no idea what type are you are expecting because of the missing annotation, also you don't even have a post object as a method parameter so I am not even sure if your method is really even supposed to be for POST.
See Also:
How to send json object from REST client using javax.ws.rs.client.WebTarget
I have an Interceptor on Struts2, and I want for some pages to redirect to the ssl version of them.
Example: http://localhost/xhtml/path.do?ossesionid=value1 to https://localhost/xhtml/path.do?ossesionid=value1
For doing this I created a Interceptor that does this:
public String intercept(ActionInvocation invocation) throws Exception {
// initialize request and response
final ActionContext context = invocation.getInvocationContext();
final HttpServletRequest request = (HttpServletRequest) context
.get(StrutsStatics.HTTP_REQUEST);
final HttpServletResponse response = (HttpServletResponse) context
.get(StrutsStatics.HTTP_RESPONSE);
// check scheme
String scheme = request.getScheme().toLowerCase();
// check method
String method = request.getMethod().toUpperCase();
// If the action class uses the SSLProtected marker annotation, then see
// if we need to
// redirect to the SSL protected version of this page
if (invocation.getAction() instanceof SSLProtected) {
if (HTTP_GET.equals(method) && SCHEME_HTTP.equals(scheme)) {
// initialize https port
String httpsPortParam = request.getSession().getServletContext().getInitParameter(HTTP_PORT_PARAM);
int httpsPort = httpsPortParam == null ? HTTPS_PORT : Integer.parseInt(httpsPortParam);
response.setCharacterEncoding("UTF-8");
URI uri = new URI(SCHEME_HTTPS, null, request.getServerName(), httpsPort, response.encodeRedirectURL(request.getRequestURI()), request.getQueryString(), null);
log.debug("Going to SSL mode, redirecting to " + uri.toString());
response.sendRedirect(uri.toString());
return null;
}
}
My problem is that I expect this
https://localhost/xhtml/path.do?ossesionid=value1
and got
https://localhost/xhtml/path.do;jsessionid=value1?osessionid=value1
And I'm Completly lost! help anyone?
i strongly suggest you to use S2-SSL plugin which is more flexible and provides a much better support to handle switch from SSL to non-SSL and vice-versa.
regarding generation of Jsessionid,JSESSIONID cookie is created/sent when session is created. Session is created when your code calls request.getSession() or request.getSession(true) for the first time. If you just want get session.You have ways to disable the creation of Jsessionid
There are number of way you can disable the creation of this id, please refer to this discussion thread.
I am still not sure what is the problem you are facing with this session-id as it is a very common case in web applications
is-it-possible-to-disable-jsessionid-in-tomcat-servlet
I am trying to create a simple app on the app engine where users log
in through their Google account, and then it adds an event to their
calendar.
And I am using Java along with Eclipse for this. I have found a simple
code online:
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Create an instance of GoogleOAuthParameters
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
oauthParameters.setScope("http://docs.google.com/feeds/");
GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(
new OAuthHmacSha1Signer());
// Remember the token secret that we stashed? Let's get it back
// now. We need to add it to oauthParameters
String oauthTokenSecret = (String) req.getSession().getAttribute(
"oauthTokenSecret");
oauthParameters.setOAuthTokenSecret(oauthTokenSecret);
// The query string should contain the oauth token, so we can just
// pass the query string to our helper object to correctly
// parse and add the parameters to our instance of oauthParameters
oauthHelper.getOAuthParametersFromCallback(req.getQueryString(),
oauthParameters);
try {
// Now that we have all the OAuth parameters we need, we can
// generate an access token and access token secret. These
// are the values we want to keep around, as they are
// valid for all API calls in the future until a user revokes
// our access.
String accessToken = oauthHelper.getAccessToken(oauthParameters);
String accessTokenSecret = oauthParameters.getOAuthTokenSecret();
// In a real application, we want to redirect the user to a new
// servlet that makes API calls. For the safe of clarity and simplicity,
// we'll just reuse this servlet for making API calls.
oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
// This is interesting: we set the OAuth token and the token secret
// to the values extracted by oauthHelper earlier. These values are
// already in scope in this example code, but they can be populated
// from reading from the datastore or some other persistence mechanism.
oauthParameters.setOAuthToken(accessToken);
oauthParameters.setOAuthTokenSecret(accessTokenSecret);
oauthParameters.setOAuthCallback("http://www.facebook.com");
oauthHelper.getUnauthorizedRequestToken(oauthParameters);
// Create an instance of the DocsService to make API calls
DocsService client = new DocsService("Malware Inc.");
// Use our newly built oauthParameters
client.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());
URL feedUrl = new URL("https://docs.google.com/feeds/default/private/full");
DocumentListFeed resultFeed = client.getFeed(feedUrl,
DocumentListFeed.class);
for (DocumentListEntry entry : resultFeed.getEntries()) {
resp.getWriter().println(entry.getTitle().getPlainText());
}
} catch (OAuthException e) {
// Something went wrong. Usually, you'll end up here if we have invalid
// oauth tokens
resp.getWriter().println("Here is the problem");
//Server shows 500 problem
} catch (ServiceException e) {
// Handle this exception
}
}
I have registered my application and added the KEY and Secret above
the function, but when I deploy it to the app engine it gives a 500
server error.
Could someone post a simple java program that uses gdata and oauth to
log in a Google user and print the contacts on the screen?
Thanks.
-Manoj
I was facing the same problem, and it took me a while to figure it out.
Actually, the problem is that your are missing some parts in the OAuth authorization process.
As you may know, it a 3-legged process:
Get an unauthorized request token
Authorize the request token
Exchange the authorized request token for an access token and make calls to Google Data with it.
In your case, you are doing step 3 directly.
So before you can call the servlet you described above, and effectively retrieve user's Google Data,
the user must have grant access to your application, by browsing to an authorization URL from his web browser.
You need a first servlet , for example accessible at http://yourapp.com/RequestAccess
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(YOUR_CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(YOUR_CONSUMER_SECRET);
OAuthHmacSha1Signer signer = new OAuthHmacSha1Signer();
GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(signer);
oauthParameters.setScope(FEED_SCOPE);
try {
oauthHelper.getUnauthorizedRequestToken(oauthParameters);
//GET THE UNAUTHORIZED TOKENS
String oauthRequestToken = oauthParameters.getOAuthToken();
String oauthTokenSecret = oauthParameters.getOAuthTokenSecret();
//SAVE THEM SOMEWEHERE (FOR EXAMPLE IN THE SESSION LIKE YOU DID)
// ....
//GET THE AUHTORIZATION URL
String authorizationURL= oauthHelper.createUserAuthorizationUrl(oauthParameters);
// YOU NOW HAVE THE AUHTORIZATION URL, SEND IT BACK TO THE USER SOMEHOW
// ( FOR EXAMPLE BY REDIRECTING THE REQUEST TO THAT URL)
// ...
} catch (OAuthException e1) {
LOGGER.error("error while getting unauthorized request token '{}' ", e1);
}
}
Once the user has navigate to that URL, and grant acces, you can now call your second servlet and it should work.
More info can be found on Google OAuth page here
Hope it helps!