Issues with OAuth Authentication in LinkedIn API - coldfusion

I'm working on a LinkedIn library for a client of mine, and am having some trouble getting through the authorization piece of the puzzle. I used the OAuth library on RIAForge and rewrote everything in order to utilize script based CFCs in CF9 and MXUnit testing. When I try to create the OAuth signature using the HMAC-SHA1 algorithm, I can never seem to match what LinkedIn is looking for. He is my method to sign the request I have:
public void function signRequest(any req){
var params = Arguments.req.getAllParameters();
var secret = "#Variables.encoder.parameterEncodedFormat(getConsumer().getConsumerSecret())#&#Variables.encoder.parameterEncodedFormat(Arguments.req.getOAuthSecret())#";
var base = '';
params = Variables.encoder.encodedParameter(params, true, true);
secret = JavaCast('string', secret).getBytes();
local.mac = createObject('java', 'javax.crypto.Mac').getInstance('HmacSHA1');
local.key = createObject('java', 'javax.crypto.spec.SecretKeySpec').init(secret, local.mac.getAlgorithm());
base = reReplaceNoCase(Arguments.req.getRequestUrl(), 'http[s]?://', '/');
params = listSort(params, 'text', 'asc', '&');
base = JavaCast('string', "#base#&#params#").getBytes();
local.mac.init(local.key);
local.mac.update(base);
Arguments.req.addParameter('oauth_signature', toBase64(mac.doFinal()), true);
}
The issue, I believe is in the secret key for the encryption. I have compared the base string to the OAuth testing tool from LinkedIn, http://developer.linkedinlabs.com/oauth-test/, and it matches perfectly, so the key used to encrypt it must me the problem. I don't have the OAuth token secret yet, so my secret is something similar to fdsa43fdsa3j&. Is that what it should be, or should the ampersand at the end be in encoded format, or something else?
Correct Method
public void function signRequest(any req){
var params = Arguments.req.getAllParameters();
var secret = "#Variables.encoder.parameterEncodedFormat(getConsumer().getConsumerSecret())#&#Variables.encoder.parameterEncodedFormat(Arguments.req.getOAuthSecret())#";
var base = '';
params = Variables.encoder.encodedParameter(params, true, true);
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());
params = listSort(params, 'text', 'asc', '&');
base = "#base#&#Variables.encoder.parameterEncodedFormat(params)#";
local.mac.init(local.key);
local.mac.update(JavaCast('string', base).getBytes());
//writeDump(toString(toBase64(mac.doFinal()))); abort;
Arguments.req.addParameter('oauth_signature', toString(toBase64(mac.doFinal())), true);
}

Ben Nadel has an example for using OAuth for connecting to Twilio. The major difference between your signing code and his is that he uses some encodings when setting up his SecretKeySpec.
Here is the relevant snip from his post:
<cfset secretKeySpec = createObject(
"java",
"javax.crypto.spec.SecretKeySpec"
).init(
toBinary( toBase64( twilioAuthKey ) ),
"HmacSHA1"
)
/>

Related

is "Client_credential" grant type can be used to access powerBI scopes?

In my project, I am trying to get embed report information from powerBI without interactive login.
so far I am able to get the information using "password" grant; when I am trying to do the same thing using "Password" grant, it is giving me "unauthorized" error.
I have hosted the application in my link to github.
explaination of the use:
Get access token to get access token for authentication.
var form = new Dictionary<string, string>();
form["grant_type"] = "password";
form["username"] = _config.Azure.Username;
form["password"] = _config.Azure.Password;
form["client_id"] = _config.Azure.ClientID;
form["client_secret"] = _config.Azure.ClientSecret;
form["scope"] = string.Join(" ",_config.Azure.Scopes);
var content = new FormUrlEncodedContent(form);
var input = new HttpInputModel
{
BaseAddress = $"{_config.Azure.AuthorityUrl}/{_config.Azure.TenantID}/",
Content = content,
Headers = new Dictionary<string, string>
{
{ "Content-Type","application/x-www-form-urlencoded" }
},
Url = "oauth2/v2.0/token"
};
use the above accesstoken came from above to get powerBI client.
var token = await _azureService.GetAccessToken();
var tokenCredentials = new TokenCredentials(token, "Bearer");
_client = new PowerBIClient(new Uri(_config.PowerBI.ApiUrl), tokenCredentials);
use the client to retrieve report information.
var workspaceId = reportInput.WorkspaceID;
var reportId = reportInput.ReportID;
var report = await _client.Reports.GetReportInGroupAsync(workspaceId, reportId);
var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
var tokenResponse = await _client.Reports.GenerateTokenAsync(workspaceId, reportId, generateTokenRequestParameters);
var output = new ReportOutput
{
Username = _config.PowerBI.Username,
EmbdedToken = tokenResponse,
EmbedUrl = report.EmbedUrl,
Id = reportInput.ReportID.ToString()
};
return output;
Conclusion: at the step 1: you can see I am using password grant
type. When I tried "client_crdentials" in place of "password" and did
not give "username" and "password". The generated "accesstoken" was
giving "Unauthorized" exception in step 3.
Note:I have tried to search in a lot of forums and some of them say we can use "serviceprincipal". But I am not able to do that.
I tried to follow the microsoft article for it and in that article they have mentioned to add SPN in pwoerBI. I tried that alot of times but it never worked for me.
Then i used another account andbit worked there so it was my accounts problem which was not allowing me to add SPN.
I already posted whole solution in github eith steps.
Here is the link:
https://github.com/Donjay2101/API--access-powerbi-without-login

AWS Cognito TOKEN endpoint fails to convert authorization code to token

My app first uses the Cognito LOGIN endpoint to obtain an Authorization Code. It then uses the TOKEN endpoint to try and obtain tokens (id_token, access_token, refresh_token) but that fails with unauthorized_client.
I do not understand why, the same client is used to access the LOGIN, and that succeeded in returning an authorization code. I'm following the documentation for the TOKEN endpoint
string clientId = ...
string clientSecret = ...
Uri redirectUri = new Uri("myapp://myhost");
string authorization_code = ... // obtained via HTTP GET on LOGIN endpoint
string accessTokenUrl = "https://<domain>.auth.<region>.amazoncognito.com/oauth2/token";
var queryValues = new Dictionary<string, string>
{
{ "grant_type", "authorization_code" },
{ "code", authorization_code },
{ "redirect_uri", redirectUri.AbsoluteUri },
{ "client_id", clientId},
};
using (HttpClient client = new HttpClient())
{
// Authorization Basic header with Base64Encoded (clientId::clientSecret)
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Basic",
Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}",
clientId,
clientSecret))));
// Url Encoded Content
var content = new FormUrlEncodedContent(queryValues);
// HTTPS POST
HttpResponseMessage response = await client.PostAsync(accessTokenUrl, content).ConfigureAwait(false);
string text = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
// test = {"error" : "unauthorized_client"}
}
The problem is two-fold:
1- System.Uri.AbsoluteUri adds a trailing / in the returned string so that my redirectUri becomes myapp://myhost/ instead of myapp://myhost
2- AWS Cognito TOKEN endpoint does not accept trailing / in a redirectURI.
The solution:
I now call redirectUri.OriginalUri instead of redirectUri.AbsoluteUri where I build the query to preserve the redirectUri as it was when I built it.
(I don't really have control over this since in my case Xamarin.Auth.OAuthAuthenticator2 calls Uri.AbsoluteUri on my behalf and transforms the redirectUri string I gave it, so I'm going to have to fix Xamarin.Auth).

How to code in app secrets and tokens for Facebook authentication in Google Scripts without having the credentials in the script?

I have a script that can obtain successfully from the Facebook oAuth API:
function getToken() {
var appId = "XXXXXX";
var clientSecret = "XXXXXXXXXXXX";
var url = "https://graph.facebook.com/oauth/access_token?client_id="+appId+"&client_secret="+clientSecret+"&grant_type=client_credentials";
var response = UrlFetchApp.fetch(url);
var queryResult = response.getContentText();
var token = queryResult.slice(13);
return(token);
}
The question is, that I prefer not to have my appId and clientSecret in the body of my script so is there a way where I can code this in without having my credentials in plain text?
Manually enter the keys and secret into the script editor as a "Script Property" (File > Project properties > Script properties) and then access them in the code using the Properties Service.
For example you could manually add:
property:APP_ID, value:'XXXXXXXX'
Then access it in the code with
var appId = PropertiesService.getScriptProperties().getProperty('APP_ID')
This technique works if you wanted to share the script on somewhere like Github, or if you only gave out view-access to the script in which case the script properties aren't visible (you should not be able to see the SPs in this script). If you give edit access to others they'll be able to see the SPs, but then you could use User Properties.
For that you need to install latest facebook SDK which uses Namespace and protected methods to get facebook data using graph api. Below is an example I worked on :
require_once ROOT . '/vendor/Facebook/autoload.php';
use Facebook\FacebookSession;
use Facebook\FacebookRedirectLoginHelper;
use Facebook\FacebookRequest;
use Facebook\FacebookResponse;
use Facebook\FacebookSDKException;
use Facebook\FacebookRequestException;
use Facebook\FacebookAuthorizationException;
use Facebook\GraphObject;
use Facebook\Entities\AccessToken;
use Facebook\HttpClients\FacebookCurlHttpClient;
use Facebook\HttpClients\FacebookHttpable;
class FacebookComponent extends Component
{
public $app_id;
public $app_secret;
public $default_graph_version;
public function __construct()
{
$this->app_id = "XXXXXXXXXXXXXXX";
$this->app_secret = "XXXXXXXXXXXXXXXXXXXXX";
$this->default_graph_version = "v2.5"; // For Offerz-develop app
}
public function getFacebookConn(){
$app_id = $this->app_id;
$app_secret = $this->app_secret;
$fb = new \Facebook\Facebook([
'app_id' => $app_id,
'app_secret' => $app_secret,
'default_graph_version' => 'v2.5',
]);
return $fb;
}
}

Posting on user's wall doesn't fail but doesn't who either

I'm having an issue where I'm posting a new message using facebook SDK 6.0 with:
var client = new FacebookClient("<target users access token>")
{
AppId = "<my app id>",
AppSecret = "<my app secret>"
};
var args = new Dictionary<string, object>
{
{"message", "A message",
};
dynamic postResult = client.Post("/me/feed", args);
The interesting part is that the postResult has an id property, but the message doesn't appear on the users feed/wall. Using the API to get all feeds doesn't return the post and manually viewing it using https://graph.facebook.com/[message_id] simple returns "false".
I've tried this with sandbox mode on and off and it makes to difference.
Any ideas on what I've done wrong?

Authenticate with MS Crm Web Service

I'm looking for a way to authenticate a user (given a username and password) via the Microsoft CRM 4.0 Web Services API. Ideally, I'd like to filter down a list of projects based on which ones the logged in user has access to. i may be able to figure out the second part but I can't find a way to authenticate the user. The way all of the cals are currently made in the web service is via:
MyWebServices.CrmService svc = new MyWebServices.CrmService();
MyWebServices.CrmAuthenticationToken token = new MyWebServices.CrmAuthenticationToken();
token.OrganizationName = "MyCRM";
token.AuthenticationType = 0;
svc.CrmAuthenticationTokenValue = token;
svc.PreAuthenticate = true;
svc.Credentials = System.Net.CredentialCache.DefaultCredentials;
svc.Credentials = new NetworkCredential("hj", "mypass", "mydomain");
Then calls can be made via the service. I guess I could potentially try to authenticate to CRM via the user's username/password but it feels wrong somehow.
If you are in an on-premise environment, you should be able to use the following code to get a valid CRM service that can be used to retrieve your projects.
public static Microsoft.Crm.SdkTypeProxy.CrmService GetCrmService(string crmServerUrl, string organizationName, System.Net.NetworkCredential networkCredential)
{
// Setup the Authentication Token
CrmAuthenticationToken crmAuthenticationToken = new CrmAuthenticationToken
{
OrganizationName = organizationName,
AuthenticationType = 0
};
var crmServiceUriBuilder = new UriBuilder(crmServerUrl) { Path = "//MSCRMServices//2007//CrmService.asmx" };
// Instantiate a CrmService
var crmService = new Microsoft.Crm.SdkTypeProxy.CrmService
{
Url = crmServiceUriBuilder.ToString(),
UseDefaultCredentials = false,
Credentials = networkCredential,
CrmAuthenticationTokenValue = crmAuthenticationToken
};
return crmService;
}