I am creating an application for a client that integrates with the LinkedIn API. I got through the authentication without too many problems, but everything there is working and now I need to make the actual requests. Primarily I am working in the Share API. I create the HTTP call with the following method:
public any function sendRequest(any req){
var param = false;
var headParams = [];
var bodyParams = [];
var call = new http(proxyserver='192.168.201.12', proxyport=8888);
var i = 1;
call.setUrl(Arguments.req.getRequestUrl());
call.setMethod(Arguments.req.getMethod());
getSigner().signRequest(Arguments.req);
headParams = Arguments.req.getParameters(true);
bodyParams = Arguments.req.getParameters();
if(arrayLen(bodyParams)){
call.addParam(
type='header',
name='Authorization',
value="OAuth#Variables.encoder.encodedParameter(Arguments.req.getParameters(true), true, false, true)#"
);
}
// Header parameters
if(!arrayLen(bodyParams)){
for(i=1; i<=arrayLen(headParams); i++){
param = headParams[i];
call.addParam(
type=Arguments.req.getParameterType(),
name=Variables.encoder.parameterEncodedFormat(param.name),
value=param.value
);
}
}
// Body parameters (should only be 1)
if(arrayLen(bodyParams)){
for(i=1; i<=arrayLen(bodyParams); i++){
param = bodyParams[i];
call.addParam(
type='xml',
value=param.value
);
}
}
return call.send().getPrefix();
}
When I sign the request, I use the following method:
public void function signRequest(any req){
var headParams = Arguments.req.getParameters(true);
var bodyParams = Arguments.req.getParameters();
var secret = "#Variables.encoder.parameterEncodedFormat(getConsumer().getConsumerSecret())#&#Variables.encoder.parameterEncodedFormat(Arguments.req.getOAuthSecret())#";
var base = '';
params = Variables.encoder.encodedParameter(headParams, true, true);
params = "#params#&#Variables.encoder.parameterEncodedFormat(bodyParams[1].value)#";
secret = toBinary(toBase64(secret));
local.mac = createObject('java', 'javax.crypto.Mac').getInstance('HmacSHA1');
local.key = createObject('java', 'javax.crypto.spec.SecretKeySpec').init(secret, local.mac.getAlgorithm());
base = "#Arguments.req.getMethod()#&";
base = base & Variables.encoder.parameterEncodedFormat(Arguments.req.getRequestUrl());
base = "#base#&#Variables.encoder.parameterEncodedFormat(params)#";
//writeDump(base) abort;
local.mac.init(local.key);
local.mac.update(JavaCast('string', base).getBytes());
Arguments.req.addParameter('oauth_signature', toString(toBase64(mac.doFinal())), true);
}
I have tried signing it with only the header parameters (usual OAuth params) and include the body parameter (xml string), but everything gives me a 401 error, so I was wondering what I should be using in my base string that gets signed for the request?
Not a proper answer to your question, but may help you.
In my case after many unsuccessful tries of using the LinkedIn API with CF8, I finally gave up / didn't have more time for it. Instead of a "proper" integration I've used the linkedin-j Java library. It finally got me going and I didn't encounter any more signing issues.
Btw for all my integrations requiring OAuth I've used this library and didn't have any signing issues as with LinkedIn API.
Related
I'm having a bit of trouble with a specific implementation of testing out my Web.API methods using RestSharp. I have been very successful in performing POSTS and GETS in my open (non-secured) methods. However, when I have to send in a token to determine access I have problems.
Here is the implementation:
I am using OWIN middleware for my Web.API. The client must post to a token service in order to get the given Token that contains their claims. All of this has been working fine.
In my test my Initializer has the following code that posts to the token service and gets back the token. This works wonderfully - returns back the token as advertised:
[TestInitialize]
public void SetupTest()
{
_verificationErrors = new StringBuilder();
_client = new RestClient
{
BaseUrl = new Uri(ConfigurationManager.AppSettings["ServicesBaseUrl"])
};
_serviceRequestPrepender = ConfigurationManager.AppSettings["ServiceRequestPrepender"];
// Initialize this by getting the user token put back for all of the tests to use.
var request = new RestRequest(string.Format("{0}{1}", _serviceRequestPrepender, ConfigurationManager.AppSettings["TokenEndpointPath"]), Method.POST);
// Add header stuff
request.AddParameter("Content-Type", "application/x-www-form-urlencoded", ParameterType.HttpHeader);
request.AddParameter("Accept", "application/json", ParameterType.HttpHeader);
// Add request body
_userName = "{test student name}";
_password = "{test student password}";
_userGuid = "{this is a guid value!!}";
_clientIdentifier = ConfigurationManager.AppSettings["ClientIdentifier"];
_applicationId = ConfigurationManager.AppSettings["ApplicationId"];
string encodedBody = string.Format("grant_type=password&username={0}&password={1}&scope={2} {3} {4} {0}"
, _userName, _password, _clientIdentifier, _userGuid, _applicationId);
request.AddParameter("application/x-www-form-urlencoded", encodedBody, ParameterType.RequestBody);
// execute the request
IRestResponse response = _client.Execute(request);
// Make sure everything is working as promised.
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.IsTrue(response.ContentLength > 0);
_token = new JavaScriptSerializer().Deserialize<Token>(response.Content).access_token;
}
Next is the following code that calls a Web.API method which passes the given token along to another Web.API method where I'm performing a GET to extract some information from my service.
[TestMethod]
public void GetUserProfileTest()
{
// Arrange
var request = new RestRequest(string.Format("{0}{1}", _serviceRequestPrepender, "api/UserProfiles/UserProfiles/Get/{appId}/{userId}/{username}"), Method.GET);
// Add header stuff
request.AddParameter("Content-Type", "application/json", ParameterType.HttpHeader);
request.AddParameter("Accept", "/application/json", ParameterType.HttpHeader);
request.AddParameter("Authorization", string.Format("{0} {1}", "Bearer", _token));
request.AddUrlSegment("appId", "1");
request.AddUrlSegment("userId", _userGuid);
request.AddUrlSegment("username", _userName);
// execute the request
IRestResponse response = _client.Execute(request);
// Make sure everything is working as promised.
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.IsTrue(response.ContentLength > 0); // do more when working
}
Next, the service is called, but I have decorated the Web.API method with a custom access security check. This is a VERY simple security check in that it only checks to see if the token is valid and not expired. Here is the IsAuthorized method of that attribute:
protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
{
// Custom Code here
return ValidityChecker.IsTokenValid(actionContext);
}
The ValidityChecker is a simple class that only checks to see if the token is valid:
public class TokenValidityChecker
{
public ClaimsPrincipal PrincipalWithClaims { get; private set; }
/// <summary>
/// Extracts out the ability to perform token checking since all Token checking attributes will need t his.
/// </summary>
/// <param name="actionContext"></param>
/// <returns></returns>
public bool IsTokenValid(System.Web.Http.Controllers.HttpActionContext actionContext)
{
bool result = false;
var principal = actionContext.RequestContext.Principal;
if (principal.GetType() == typeof(ClaimsPrincipal))
{
PrincipalWithClaims = (ClaimsPrincipal)principal;
result = PrincipalWithClaims.Identity.IsAuthenticated;
}
// Custom Code here
return result;
}
}
So, with the background in place - here is the question. As you can see, normally, when the service is called the ValidityChecker will receive an HttpActionContext. Along with that, the RequestContext.Principal of that HttpActionContext will normally be of type ClaimsPrincipal.
However, when running from a unit test and using RestSharp it is, of course, a WindowsPrincipal.
Is there a way using RestSharp to make that a ClaimsPrincipal? I've tried to ensure the token is included in the header using the Authorization parameter, but have not had any luck.
Well - If I would simply read the details of my own code I could have completed this long ago.
The answer was VERY simple. The code in the question adds the token to the parameters, but does not annotate it as HttpHeader. I forgot to put that into the method call. Here is the line that fixed it:
request.AddParameter("Authorization", string.Format("{0} {1}", "Bearer", _token), ParameterType.HttpHeader);
The "ParameterType.HttpHeader" in the method call did the trick.
I'm trying to call a webservice using username/pwd using the below client but I don't see the username/password being set in the headers
Client code
AttachmentWSImplService service = new AttachmentWSImplService();
AttachmentWS aws = service.getAttachmentWS();
BindingProvider bindingProvider = (BindingProvider) aws;
SOAPBinding sopadBinding = (SOAPBinding) bindingProvider.getBinding();
sopadBinding.setMTOMEnabled(true);
bindingProvider.getRequestContext().put(bindingProvider.USERNAME_PROPERTY,"p3xferdt");
bindingProvider.getRequestContext().put(bindingProvider.PASSWORD_PROPERTY,"92mnGg1Cb14D9hVhG1W5fZra4UI=");
Server code
SOAPMessageContext ctx = (SOAPMessageContext) wsCtx
.getMessageContext();
java.util.Map<java.lang.String, java.util.List<java.lang.String>> headers = (Map<String, List<String>>) ctx
.get(MessageContext.HTTP_REQUEST_HEADERS);
if (headers.keySet() != null && !headers.keySet().isEmpty()) {
Iterator<String> keys = headers.keySet().iterator();
while (keys.hasNext()) {
String key = (String) keys.next();
logger.info("HeaderKey->" + key);
logger.info("Header values->" + headers.get(key));
// getting Basic Authentication
String tmpusername = getUsernameFromAuthentication(key,
headers.get(key).toString());
Code looks ok to me, should work fine.
Anyways try accessing Request Header by
Headers headers = ex.getRequestHeaders();
List<String> ulist = headers.get(BindingProvider.USERNAME_PROPERTY);
List<String> plist = headers.get(BindingProvider.PASSWORD_PROPERTY);
PS: Remember USERNAME_PROPERTY is static string from BindingProvider interface, can be accessed in Static way. (Coding standards :))
while make a webservice call out I am getting below error:
Web service callout failed: Unexpected element. Parser was expecting element 'http://schemas.xmlsoap.org/soap/envelope/:Envelope' but found ':HTML'
Please see below code which I am trying for this:
public class TestUtility_Cls{
public list<Test_webService.KeyValuePair> IOG_pair = new list<Test_webService.KeyValuePair>();
public pageReference calltestServices(){
I_pair = new list<Test_webService.KeyValuePair>();
Test_webService.webPort bindobj = new Test_Iwebervice.RtPort();
bindobj.clientCertName_x = 'xxxxxxxxxxxxxx';
bindobj.timeout_x = 120000;
bindobj.inputHttpHeaders_x = new Map<String, String>();
bindobj.inputHttpHeaders_x.put('Authorization', 'xxxxxxxxx');
Test_webService.KeyValuePair I_KeyValue = new Test_webService.KeyValuePair();
I_KeyValue.key = 'SessionId';
I_KeyValue.value = 'Carrie09';
I_pair.add(I_KeyValue);
I_KeyValue = new Test_webService.KeyValuePair();
I_KeyValue.key = 'CR';
I_KeyValue.value = 'ExOffer';
I_pair.add(I_KeyValue);
Test_webService.ArrayOfKeyValuePair kevapair = new Test_webService.ArrayOfKeyValuePair();
kevapair.attribute = I_pair;
Test_webService.ProcessEventResponse_element IResp = new Test_webService.ProcessEventResponse_element();
IResp = bindingobj.ProcessEvent('QA', 'GetOffers', kevapair);
return null;
}
}
Here I am using WSDL generated class's method.
Can someone help on this. How to resolve it?
Thanks,
public pageReference calltestServices(){
I think above method refers a html page reference from which you are extracting your input data.You are forming your input request in html format while your webservice is expectng soap envelope. I think you need to wrap or convet or edit your request, formed in above method as soap envelope, then only your server accept it.
I am trying to pull orders from Catalook using the remote API. Here is my code:
CATALooKRemote.RemoteController remote = new CATALooKRemote.RemoteController();
remote.Url = "http://localhost/Customers/DotNetNuke_Community_06.02.04_Install/DesktopModules/CATALooKStore/remote.asmx";
bool log = remote.Login(0, "host", "dnnhost");
Response.Write(log);
var orders = remote.GetOrders(new DateTime(2009, 1, 1), new DateTime(2014, 1, 1), -1);
foreach (var a in orders)
{
}
//throws null reference exception
Response.Write(orders.Count());
I have only one order in the system, but I cannot query it using this method. The order has paid status.
I've never used the CATALookRemote service but looking at the WSDL, don't you need to pass the username, password and portal id as well?
SRVRemote.RemoteControllerSoapClient remote = new SRVRemote.RemoteControllerSoapClient();
List<SRVRemote.OrderDetailsRemote> oOrders = null;
oOrders = remote.GetOrders(System.DateTime.FromOADate(0), System.DateTime.Today, -1, 0, "MyUsername", "MyPassword");
foreach (SRVRemote.OrderDetailsRemote order in oOrders) {
//Do something
}
How do I create a webservice using Mono For Android? It seems like everything is about consuming a webservice, and not really about creating one.
I've tried using this: http://www.mono-project.com/Writing_a_WebService
But System.Web.Services.WebService doesn't exist. System.ServiceModel hasn't been translated yet either. Does anyone have clues on how to create a webservice on Mono For Android?
Thanks
I have now tried to implement the following code and tried to run it in the emulator, but the request I make either through my browser or through a REST client, never reaches the HandleRequest.
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
var startBtn = FindViewById<Button>(Resource.Id.StartBtn);
stopBtn.Clickable = false;
startBtn.Click += SetupListener;
}
private void SetupListener(object sender, EventArgs e) {
_httpListener = new HttpListener();
_httpListener.Prefixes.Add("http://*:9876/");
_httpListener.Start();
_httpListener.BeginGetContext(HandleRequest, _httpListener);
}
private void HandleRequest(IAsyncResult result) {
var context = _httpListener.EndGetContext(result);
var response = "<html>Hello World</html>";
var buffer = Encoding.UTF8.GetBytes(response);
context.Response.ContentLength64 = buffer.Length;
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
context.Response.OutputStream.Close();
_httpListener.BeginGetContext(HandleRequest, _httpListener);
}
I have tried making request like the following: http:// localhost:9876/ , http:// 10.1.1.190:9876/ and http:// 10.0.2.2:9876/ but none of them actually reaches into the application.