PowerShell has a great function in the Az.Accounts library - "Connect-AzAccount" - that allows me to authenticate against my Azure instance and publish APIM's easily. I need to port the code over to c# and am unable to find an easy equivalent.
Has anyone found a straightforward way to do this? The Azure world / libraries seem to be updating frequently, along with the many security aspects. It's difficult to find a recent, relevant example.
My ultimate goal is to authenticate against Azure, then publish API's to the API Gateway.
The PowerShell code:
$user = "account#domain.com"
$password = ConvertTo-SecureString -String "password goes here" -AsPlainText -Force
$azAccount = #{
subscription = "subscription-guid-goes-here"
credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $user,$password
}
Connect-AzAccount #azAccount
Currently, Azure Management Library for .NET can only be used to manage partial Azure resources. However, Azure API Management is not included.
So, I suggest you use Azure REST API to manage your resources.
As Azure REST APi is protected under Azure AD. So, the first step is to acquire an accesstoken for authentication.
Here is a sample by using Microsoft.IdentityModel.Clients.ActiveDirectory package
static string GetToken()
{
string tenantId = "your tenant id or name, for example: hanxia.onmicrosoft.com";
string clientId = "1950a258-227b-4e31-a9cf-717495945fc2"; // it is a public client for every tenant.
string resource = "https://management.core.windows.net/";
string username = "user name, jack#hanxia.onmicrosoft.com";
string password = "password, D******";
var upc = new UserPasswordCredential(username, password);
var context = new AuthenticationContext("https://login.microsoftonline.com/" + tenantId);
AuthenticationResult result = context.AcquireTokenAsync(resource, clientId, upc).Result;
return result.AccessToken;
}
After that, you can call Azure REST API along with adding authorization header. Here is a POST request sample:
public static string postRequest(string url, string access_token, string data)
{
byte[] buffer = null;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "post";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Bearer " + access_token);
//request.Headers.Add("other header", "it's value");
if (data != null)
buffer = Encoding.UTF8.GetBytes(data);
else
buffer = Encoding.UTF8.GetBytes("");
request.ContentLength = buffer.Length;
request.GetRequestStream().Write(buffer, 0, buffer.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
return response.StatusCode + " " + reader.ReadToEnd();
}
}
the existing answer is a bit odd, its linking some old depreciated library. Official library supports "managing" Api Management. That would be the preferred way of managing Azure resources with C# and you dont have to recreate anything.
Related
How to add profile scope and email scopes in Google OAuth, i am using the code given below.
string tokenRequestURI = "https://www.googleapis.com/oauth2/v4/token";
string tokenRequestBody = string.Format("code={0}&redirect_uri={1}&client_id={2}&code_verifier={3}&client_secret={4}&scope=&grant_type=authorization_code",
code,
System.Uri.EscapeDataString(redirectURI),
clientID,
code_verifier,
clientSecret
);
// sends the request
HttpWebRequest tokenRequest = (HttpWebRequest)WebRequest.Create(tokenRequestURI);
tokenRequest.Method = "POST";
tokenRequest.ContentType = "application/x-www-form-urlencoded";
tokenRequest.Accept = "Accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
byte[] _byteVersion = Encoding.ASCII.GetBytes(tokenRequestBody);
tokenRequest.ContentLength = _byteVersion.Length;
Stream stream = tokenRequest.GetRequestStream();
await stream.WriteAsync(_byteVersion, 0, _byteVersion.Length);
stream.Close();
you are not sending any scopes in your tokenRequestBody have you tried adding them there?
string tokenRequestBody = string.Format("code={0}&redirect_uri={1}&client_id={2}&code_verifier={3}&client_secret={4}&scope={5}&grant_type=authorization_code",
code,
System.Uri.EscapeDataString(redirectURI),
clientID,
code_verifier,
clientSecret,
"email profile"
);
You should really look into use the Google .net client library rather than doing this all manually.
This is more about how to get HttpWebRequest to work or even if HttpWebRequest is the right implementation. I've let my C# and .Net skill lapse the past few year, so I hope I can be forgiven for that.
I trying to hit a secure web service that requires client authentication. I have four certs to hit this with.
• Root Certificate
• Intermediate Root Certificate
• Device Certificate
• Private Key
The server is Java and these certs are in .jks form trustore and keystore. I pulled them into .pem files.
So, I failed on the C# client side, so I thought I'd write a little Python snippet to make sure at least the server side is working as expected. Twenty minutes later, I'm making secure posts. Here's that code:
# Keys
path = "C:\\path\\"
key = path + "device.pem"
privkey = path + "device_privkey.pem"
CACerts = path + "truststore.concat" # root & intermediate cert
def post():
url = "/url"
headers = {'Content-Type': 'application/xml'}
## This section is HTTPSConnection
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
context.verify_mode = ssl.CERT_OPTIONAL
context.load_cert_chain(key, privkey, password='password')
context.verify_mode = ssl.CERT_NONE
context.load_verify_locations(CACerts)
conn = http.client.HTTPSConnection(host, port=8080, context=context)
conn.request("POST", url, registrationBody, headers)
response = conn.getresponse()
regresp = response.read()
The concat certificate is the concatenation of the root and intermediate certificates.
Are you with me?
Now to my C#/.Net headache.
This my attempt. I clearly don't know what I'm doing here.
public async Task POSTSecure(string pathname, string body)
{
string path = "C:\\path";
string key = path + "device.pem";
string privkey = path + "device_privkey.pem";
string CACerts1 = path + "vtn_root.pem";
string CACerts2 = path + "vtn_int.pem";
try
{
// Create certs from files
X509Certificate2 keyCert = new X509Certificate2(key);
X509Certificate2 rootCert = new X509Certificate2(CACerts1);
X509Certificate2 intCert = new X509Certificate2(CACerts2);
HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create("https://" + host + ":" + port + pathname);
ServicePoint currentServicePoint = request.ServicePoint;
// build the client chain?
request.ClientCertificates.Add(keyCert);
request.ClientCertificates.Add(rootCert);
request.ClientCertificates.Add(intCert);
Console.WriteLine("URI: {0}", currentServicePoint.Address);
// This validates the server regardless of whether it should
request.ServerCertificateValidationCallback = ValidateServerCertificate;
request.Method = "POST";
request.ContentType = "application/xml";
request.ContentLength = body.Length;
using (var sendStream = request.GetRequestStream())
{
sendStream.Write(Encoding.UTF8.GetBytes(body), 0, body.Length);
}
var response = (HttpWebResponse)request.GetResponse();
}
catch (Exception e)
{
Console.WriteLine("Post error.");
}
}
Thanks for any help or a pointer to a decent tutorial.
[Edit] More info. On the server side, the debugging points to an empty client certificate chain. This is right after it reports serverhello done.
Okay, I think I was pretty close in the original, but I solved it this way:
request.ClientCertificates = new X509Certificate2Collection(
new X509Certificate2(
truststore,
password));
The "trustore" file is a .p12 containing the certificates listed above. The .p12 truststore can be created from the .jks truststore through keytool and openssl. Lots of info out there on how to do that.
I am trying to use OAuth 2 in my Asp.net app (C#). The problem is I need to use a shared google account. To do this, my plan is to seed the authentication with a token, an expiration date, and a refresh token, and then when authentication is required I check the expiration date and use the refresh token.
The example I've been using for Authentication looks like this:
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows an application to upload files to the
// authenticated user's YouTube channel, but doesn't allow other types of access.
new[] { YouTubeService.Scope.YoutubeUpload },
"user",
CancellationToken.None
);
}
And doesn't seem to contain an object with a refresh token.
How do I get the Refresh token and expiration date?
The solution was to do a post action and parse the results manually instead of using any of the Google classes.
string gurl = "code=" + code + "&client_id=" + client_id +
"&client_secret=" + client_secret + "&redirect_uri=" + redirect_uri + "&grant_type=" + grant_type;
string url = "https://www.googleapis.com/oauth2/v3/token";
// creates the post data for the POST request
string postData = (gurl);
// create the POST request
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Host ="www.googleapis.com";
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentLength = postData.Length;
// POST the data
using (StreamWriter requestWriter2 = new StreamWriter(webRequest.GetRequestStream()))
{
requestWriter2.Write(postData);
}
//This actually does the request and gets the response back
HttpWebResponse resp = (HttpWebResponse)webRequest.GetResponse();
string googleAuth;
using (StreamReader responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream()))
{
//dumps the HTML from the response into a string variable
googleAuth = responseReader.ReadToEnd();
}
From there I mainly need to parse the googleAuth string to get at the Token, the Refresh Token, and the expiration period. I kept expecting there to be a solution inside the Google classes for what must be an incredibly common request, but apparently I'll be creating my own class.
UPDATE: I figured it out and posted the answer below.
All I'm trying to do is update any file attribute. Description, name, anything, but no matter how I format it I get a 403.
I need to be able to modify a file so it can be shared via the Box API from a cloud app. I'm updating someone else's code from V1, but they are no longer available... I've tried many things but mostly just get 403 Forbidden errors.
There are no issues with OAuth2, that works fine and I can list files and folders, but can not modify them. This question is about sharing, but I can't change a description either. The box account is mine and I authenticate with my admin credentials. Any suggestions would be appreciated.
Here is the method I am using. I pass in the fileId and token and I've left out try/catch etc. for brevity.
string uri = string.Format("https://api.box.com/2.0/files/{0}", fileId);
string body = "{\"shared_link\": {\"access\": \"open\"}}";
byte[] postArray = Encoding.ASCII.GetBytes(body);
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
client.Headers.Add("Authorization: Bearer " + token);
var response = client.UploadData(uri, postArray);
var responseString = Encoding.Default.GetString(response);
}
Thanks.
Okay, My Homer Simpson moment...
UploadData is a POST, I needed to do a PUT. Here is the solution.
string uri = String.Format(UriFiles, fileId);
string response = string.Empty;
string body = "{\"shared_link\": {\"access\": \"open\"}}";
byte[] postArray = Encoding.ASCII.GetBytes(body);
try
{
using (var client = new WebClient())
{
client.Headers.Add("Authorization: Bearer " + token);
client.Headers.Add("Content-Type", "application/json");
response = client.UploadString(uri, "PUT", body);
}
}
catch (Exception ex)
{
return null;
}
return response;
try changing your content type to 'multipart/form-data'?
I just looked up the api at: https://developers.box.com/docs/#files-upload-a-file
and it looks like the server is expecting a multipart post
here is stack overflow post on posting multipart data:
ASP.NET WebApi: how to perform a multipart post with file upload using WebApi HttpClient
I am using c# to create shared access signatures for new resources (The user should have create privileges to create new resources on my storage account).
The MS documentation is out of date and I can't seem to get it to work using the different blog posts I've gone through.
Right now my code looks like so:
public static string GetBlobSharedAccessSignitureUrl(CloudBlobContainer container,string nameOfBlobToCreateSaSfor)
{
var blob = container.GetBlockBlobReference(nameOfBlobToCreateSaSfor);
var policy = new SharedAccessBlobPolicy
{
SharedAccessExpiryTime = DateTime.Now.AddHours(1),
Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read
};
container.GetSharedAccessSignature(policy);
string sas = blob.GetSharedAccessSignature(policy);
return blob.Uri.AbsoluteUri + sas;
}
and the returned url (for my local machine) looks like this (what seems to be correct)
http://127.0.0.1:10000/devstoreaccount1/photos/photos_4.jpg?sv=2012-02-12&se=2013-01-20T10%3A13%3A17Z&sr=b&sp=rw&sig=xxx
I started the Azure storage simulator and through fiddler tried to POST to this URL (also tried PUT)
I am getting errors (404 or 400 , depends on different code for this function that I have tried)
Do I need to do something else? (In the old examples I saw them create a resource in that location before hand - which I've tried as well but didn't work either...)
Azure SDK version is 2.0 so the MS blog posts (and other tutorials) before October 2012 are broken (also according to MS dev blog http://blogs.msdn.com/b/windowsazurestorage/archive/2012/10/29/windows-azure-storage-client-library-2-0-breaking-changes-amp-migration-guide.aspx)
any help would be appreciated
If you're posting through Fiddler or through your code, please make sure you add "x-ms-blob-type" request header and set it's value as "BlockBlob". Take a look at this sample code where it tries to upload a file:
FileInfo fInfo = new FileInfo(fileName);//fileName is the full path of the file.
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(blobSaSUrl);
NameValueCollection requestHeaders = new NameValueCollection();
requestHeaders.Add("x-ms-blob-type", "BlockBlob");
req.Method = "PUT";
req.Headers.Add(requestHeaders);
req.ContentLength = fInfo.Length;
byte[] fileContents = new byte[fInfo.Length];
using (FileStream fs = fInfo.OpenRead())
{
fs.Read(fileContents, 0, fileContents.Length);
using (Stream s = req.GetRequestStream())
{
s.Write(fileContents, 0, fileContents.Length);
}
using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
{
}
}
Create a SAS token that's valid for one hour.
BlobSasBuilder sasBuilder = new BlobSasBuilder()
{
BlobContainerName = containerName,
BlobName = blobName,
Resource = "b",
StartsOn = DateTimeOffset.UtcNow,
ExpiresOn = DateTimeOffset.UtcNow.AddHours(1)
};
Specify read permissions for the SAS.
sasBuilder.SetPermissions(BlobSasPermissions.Read);
Use the key to get the SAS token.
string sasToken = sasBuilder.ToSasQueryParameters(key, accountName).ToString();
Construct the full URI, including the SAS token.
UriBuilder fullUri = new UriBuilder()
{
Scheme = "https",
Host = string.Format("{0}.blob.core.windows.net", accountName),
Path = string.Format("{0}/{1}", containerName, blobName),
Query = sasToken
};