I am facing one issue while integrating AWS Iot SDK in my Xamarin.Android app.
I am creating basic app just to connect to mqtt through AWS Iot to subscribe to topics and and publish messages to that topic.
I am getting "java.security.UnrecoverableKeyException:no match" in getTempKeystore method in AWSIotKeystoreHelper class.
I have created a bks file using bouncycastle which has both certificate and key.(I have created this certificate through AWS resource)
I have followed the exact same steps as mentioned in the link:
https://github.com/awslabs/aws-sdk-android-samples/tree/master/AndroidPubSub
Here is my code:
private static String CUSTOMER_SPECIFIC_ENDPOINT = "";
private static String COGNITO_POOL_ID = "";
private static String AWS_IOT_POLICY_NAME = "";
private static Regions MY_REGION = Regions.UsEast2;
private static String KEYSTORE_NAME = "";
private static String KEYSTORE_PASSWORD = "";
private static String CERTIFICATE_ID = "";
clientId = UUID.RandomUUID().ToString();
credentialsProvider = new CognitoCachingCredentialsProvider(
Android.App.Application.Context, // context
COGNITO_POOL_ID, // Identity Pool ID
MY_REGION // Region
);
Region region = Region.GetRegion(MY_REGION);
mqttManager = new AWSIotMqttManager(clientId, CUSTOMER_SPECIFIC_ENDPOINT);
mqttManager.KeepAlive = 10;
AWSIotMqttLastWillAndTestament lwt = new AWSIotMqttLastWillAndTestament("my/lwt/topic", "Android client lost connection", AWSIotMqttQos.Qos0);
mqttManager.MqttLastWillAndTestament = lwt;
mIotAndroidClient = new AWSIotClient(credentialsProvider);
mIotAndroidClient.SetRegion(region);
keystorePath = FilesDir.AbsolutePath;
keystoreName = KEYSTORE_NAME;
keystorePassword = KEYSTORE_PASSWORD;
certificateId = CERTIFICATE_ID;
if ((bool)AWSIotKeystoreHelper.IsKeystorePresent(keystorePath, keystoreName))
{
if ((bool)AWSIotKeystoreHelper.KeystoreContainsAlias(certificateId, keystorePath, keystoreName, keystorePassword))
{
clientKeyStore = AWSIotKeystoreHelper.GetIotKeystore(certificateId, keystorePath, keystoreName, keystorePassword);
}`
else
{
Log.Info(LOG_TAG, "Key/cert " + certificateId + " not found in keystore.");
}
}
else
{
Log.Info(LOG_TAG, "Keystore " + keystorePath + "/" + keystoreName + " not found.");
}`
I was able to resolve this issue.I was using openssl pkcs12 to convert the certificates and keys into .p12 format. And then using the bouncycastle jar to convert the .p12 keystore to .bks format as android supports only BKS format. Instead of using bouncycastle i used Portecle.I referred to the following links for all the further conversion process :
Downloading portecle
http://certificate.fyicenter.com/942_Portecle_Downloading_and_Installing_Portecle_1.7.html
Conversion from .p12 to .bks
http://portecle.sourceforge.net/change-keystore-type.html
Related
I need to create automaion client for Azure webhook.
Following code is written by me to get AutomationManagementClient Value.
var cert = new X509Certificate2(Convert.FromBase64String(ConfigurationManager.AppSettings["CertBase64String"]));
var creds[![enter image description here][1]][1] = new CertificateCloudCredentials(ConfigurationManager.AppSettings["SubscriptionId"], cert);
AutomationManagementClient automationManagementClient = new AutomationManagementClient(creds);
I need that certificate string i.e. CertBase64String value as I don't know from where I will get that value.
Help me...
This error I am getting after updating as per your answer.
If you want to create the automation client, I suggest you try to use the ARM way to operate the automation. The following is the demo code works correctly on my side.
Prepare: Registry an AD application and assign role to applcation, more details please refer to Azure official tutorials. After that we can get tenantId, appId, secretKey from the Azure Portal.
We could use the following code to get the token
var tenantId = "tenantId";
var context = new AuthenticationContext($"https://login.windows.net/{tenantId}");
var clientId = "application Id";
var clientSecret = "client secret";
var resourceGroup = "resource group";
var automationAccount = "automationAccount";
var subscriptionId = "susbscriptionId";
var token = context.AcquireTokenAsync(
"https://management.azure.com/",
new ClientCredential(clientId, clientSecret)).Result.AccessToken;
if you use the Microsoft.Azure.Management.Automation Version <= 2.0.4 please try the following code.
var automationClient = new AutomationManagementClient(new TokenCloudCredentials(subscriptionId,token));
var webhook = automationClient.Webhooks.CreateOrUpdate(resourceGroup, automationAccount,new WebhookCreateOrUpdateParameters
{
Properties = new WebhookCreateOrUpdateProperties
{
ExpiryTime = DateTimeOffset.Now.AddDays(1),
IsEnabled = false,
Parameters = parameters,
Runbook = new RunbookAssociationProperty
{
Name = "xxxx"
},
Name = "xxxx",
Uri = "https://xxxx.xx"
}
});
if use the Microsoft.Azure.Management.Automation Version 3.0.0-preview, please try to the following case.
var automationClient = new AutomationClient(new TokenCredentials(token)) {SubscriptionId = subscriptionId};
var webhook = automationClient.Webhook.CreateOrUpdate(resourceGroup, automationAccount, "webhookName",
new WebhookCreateOrUpdateParameters
{
ExpiryTime = DateTime.Now.AddDays(1),
IsEnabled = false,
Parameters = parameters,
Name = "xxxxx",
Runbook = new RunbookAssociationProperty
{
Name = "xxxxx"
},
Uri = "https://xxx.xxx"
});
Update:
You could set the Parameters = null or if you have parameter, you could define the parameters as dictionary. Please also add the Name = "xxxx" in the code.
var parameters = new Dictionary<string, string> {{"test", "test"}};
var webhook = automationClient.Webhooks.CreateOrUpdate(resourceGroup, automationAccount,new WebhookCreateOrUpdateParameters
{
Properties = new WebhookCreateOrUpdateProperties
{
ExpiryTime = DateTimeOffset.Now.AddDays(1),
IsEnabled = false,
Parameters = parameters,
Runbook = new RunbookAssociationProperty
{
Name = "xxxx"
},
Name = "xxxx",
Uri = "https://xxxx.xx"
}
});
I test it on my side, it works correctly
"CertBase64String" will get by passing thumb-print of that certificate to following fucntion.
internal static X509Certificate2 GetCertificateFromthumbPrint(String certThumbPrint) {
X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
//Find the certificate that matches the thumbprint.
X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, certThumbPrint, false);
certStore.Close();
//Get the first cert with the thumbprint
X509Certificate2 cert = (certCollection.Count > 0) ? certCollection[0] : null;
return cert;
}
I trying get an access token from Dropbox Sync & Datastore xamarin component in Xamarin iOS project.I have used dropnet to get the access token but I'm getting an http exception :( let me know where I'm doing wrong
private static void GetAccessToken()
{
try
{
const string DropboxSyncKey = "XXXXXXXX";
const string DropboxSyncSecret = "XXXXXX";
//this url is obtained fromDBAccountManager.SharedManager.HandleOpenURL(url);
string token = "db-XXXXXX://1/connect?oauth_token_secret=XXXXXXX&state=xXXXXXXX&uid=XXXXXX&oauth_token=xXXXXXXXX";
token = token.Substring(token.LastIndexOf("&") + 13);
string stoken = "db-XXXXXX://1/connect?oauth_token_secret=XXXXXXX&state=xXXXXXXX&uid=XXXXXX&oauth_token=xXXXXXXXX";
int indexof = stoken.IndexOf("?") + 20;
int lastindex = stoken.IndexOf("&") - indexof;
string secrettoken = stoken.Substring(indexof, lastindex);
var client = new DropNetClient(DropboxSyncKey, DropboxSyncSecret, token, secrettoken);
var accesskey = client.GetAccessToken();
Console.WriteLine(token);
Console.WriteLine(secrettoken);
Console.WriteLine(accesskey);
}
catch (Exception)
{
}
}
I was looking for a way to Authenticate an IMAP session with google's Service account
But Since we already use Chilkat how do we do it, I found the following:
http://www.cknotes.com/imap-authentication-using-oauth/
allowing me to send a raw command:
imap.SendRawCommand("AUTHENTICATE XOAUTH <base64_data>");
This shows how to strucure the command:
https://developers.google.com/gmail/xoauth2_protocol
But having trouble putting it all together.
limilabs puts things together nicely in this example:
http://www.limilabs.com/blog/oauth2-gmail-imap-service-account
They have a neat imap.LoginOAUTH2(userEmail, credential.Token.AccessToken); that wraps things up into a command. How do I do this as a raw command for Chilkat?
const string serviceAccountEmail = "service-account-xxxxxx#developer.gserviceaccount.com";
const string serviceAccountCertPath = #"service-xxxxxx.p12";
const string serviceAccountCertPassword = "notasecret";
const string userEmail = "user#domain.com";
X509Certificate2 certificate = new X509Certificate2(
serviceAccountCertPath,
serviceAccountCertPassword,
X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { "https://mail.google.com/" },
User = userEmail
}.FromCertificate(certificate));
bool success = credential.RequestAccessTokenAsync(CancellationToken.None).Result;
using (Chilkat.Imap imap = new Chilkat.Imap())
{
imap.UnlockComponent("unlock-code");
imap.Ssl = true;
imap.Port = 993;
imap.Connect("imap.gmail.com");
var authString = String.Format("user={0}" + "\x001" + "auth=Bearer {1}" + "\x001" + "\x001",userEmail, credential.Token.AccessToken);
var encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(authString));
string response = imap.SendRawCommand("AUTHENTICATE XOAUTH2 " + encoded);
imap.SelectMailbox("Inbox");
bool bUid;
bUid = false;
string mimeStr;
int i;
int n;
n = imap.NumMessages;
for (i = 1; i <= n; i++)
{
// Download the email by sequence number.
mimeStr = imap.FetchSingleAsMime(i, bUid);
Chilkat.Email chilkatEmail = new Chilkat.Email();
chilkatEmail.SetFromMimeText(mimeStr);
Console.WriteLine(chilkatEmail.Subject);
}
imap.CloseMailbox("Inbox");
Console.ReadLine();
}
}
I'm attempting to replicate the OAuth steps normally done via the "Connect to QuickBooks" button using HttpWebRequest/HttpWebResponse.
It's easy at first grabbing the request token and generating the authorization link:
private const string oauthBaseUrl = "https://oauth.intuit.com/oauth/v1";
private const string urlRequestToken = "/get_request_token";
private const string urlAccessToken = "/get_access_token";
private const string verifyUrl = "https://appcenter.intuit.com";
private const string authorizeUrl = "https://appcenter.intuit.com/Connect/Begin";
...
var consumerContext = new OAuthConsumerContext
{
ConsumerKey = System.Utilities.Cryptography.Encryption.ConvertToUnsecureString(ckSS),
ConsumerSecret = System.Utilities.Cryptography.Encryption.ConvertToUnsecureString(csSS),
SignatureMethod = SignatureMethod.HmacSha1
};
IOAuthSession session = new OAuthSession(consumerContext, oauthBaseUrl + urlRequestToken, authorizeUrl, oauthBaseUrl + urlAccessToken);
IToken requestToken = session.GetRequestToken();
string authorizationLink = session.GetUserAuthorizationUrlForToken(requestToken, callbackUrl);
Then I walk through grabbing the request verification code that is generated in the set-cookie string when requesting the site at the authorization link:
var requestAuth = (HttpWebRequest) WebRequest.Create(authorizationLink);
requestAuth.Method = "GET";
requestAuth.ContentType = "application/x-www-form-urlencoded";
requestAuth.Accept = "text/html, application/xhtml+xml, */*";
requestAuth.Headers.Add("Accept-Encoding", "gzip, deflate");
requestAuth.Headers.Add("Accept-Language", "en-us");
requestAuth.Host = "appcenter.intuit.com";
requestAuth.KeepAlive = true;
var responseAuth = (HttpWebResponse) requestAuth.GetResponse();
Stream answerAuth = responseAuth.GetResponseStream();
var _answerAuth = new StreamReader(answerAuth);
string htmlAuth = _answerAuth.ReadToEnd();
// Need to grab the request verification code embedded in the set-cookie string
string cookies = responseAuth.Headers.Get("Set-Cookie");
int idx = cookies.IndexOf("__RequestVerificationToken", StringComparison.Ordinal);
if (idx > 0)
{
int startIndex = cookies.IndexOf("=", idx, StringComparison.InvariantCultureIgnoreCase);
int endIndex = cookies.IndexOf(";", startIndex + 1, StringComparison.InvariantCultureIgnoreCase);
requestVerificationCode = cookies.Substring(startIndex + 1, endIndex - (startIndex + 1));
postDataString += requestVerificationCode;
}
As I understand it, the request verification code is needed in order to get the OAuth verification code that is returned in the postdata appended to the callback URL, which is in turn needed to get the access token.
This is where the difficulty begins. Using Fiddler2, I find that the login URL for generating the OAuth verification code is https://appcenter.intuit.com/Account/LogOnJson. But no matter how much I try to replicate the HTTP POST using HttpWebRequest, all I get in return is a 500 error. I'm wondering if anyone has a working example of this step? Is this even possible? I hope so, because the alternative of pulling up IE and walking through the same steps like a macro is too ugly.
Any help on this? Thanks!
You can download the dotnet sample app for understanding how the OAUTH flow works:
https://github.com/IntuitDeveloperRelations/IPP_Sample_Code
Set your app keys in web.config.
I am trying to generate a JWT in Apex on Force.com but keep getting a 400 "error" : "invalid_grant". I've tried numerous variations, but just can't get a valid response. My clientEmailAddress is correct (eg ###developer.gserviceaccount.com). I extracted the value of my Private Key using openSSL. I wrote a method to base64URL encode based on other posts on the board. Any help would be greatly appreciated.
public static String base64URLencode(Blob input){
String output = encodingUtil.base64Encode(input);
output = output.replace('+', '-');
output = output.replace('/', '_');
while ( output.endsWith('=')){
output = output.subString(0,output.length()-1);
}
return output;
}
public static void generateJWT(){
Long rightNow = (dateTime.now().getTime()/1000)+1;
JSONGenerator gen = JSON.createGenerator(false);
gen.writeStartObject();
gen.writeStringField('iss',clientEmailAddress);
gen.writeStringField('scope','https:\\/\\/www.googleapis.com\\/auth\\/prediction');
gen.writeStringField('aud','https:\\/\\/accounts.google.com\\/o\\/oauth2\\/token');
gen.writeNumberField('exp',rightNow+300);
gen.writeNumberField('iat',rightNow);
String claimSet = gen.getAsString().trim();
String header = '{"alg":"RS256","typ":"JWT"}';
String signatureInput = base64URLencode(blob.valueOf(header))+'.'+base64URLencode(blob.valueOf(claimSet));
Blob signature = crypto.sign('RSA', blob.valueOf(signatureInput), encodingUtil.base64decode(privatekey));
String jwt = signatureInput+'.'+base64URLencode(signature);
http h = new http();
httpRequest req = new httpRequest();
req.setHeader('Content-Type','application/x-www-form-urlencoded');
req.setMethod('POST');
req.setBody('grant_type='+encodingUtil.urlEncode('urn:ietf:params:oauth:grant-type:jwt-bearer','UTF-8')+'&assertion='+encodingUtil.urlEncode(jwt,'UTF-8'));
req.setEndpoint('https://accounts.google.com/o/oauth2/token');
httpResponse res = h.send(req);
}
I think the method name is Base64encode but not base64urlencode