How to create CallCredentials from SslCredentials and token string - c#

I am porting a gRPC client from python to c#. Both the python client and the c# client are using the gRPC Framework from grpc.io.
The python client uses the following code to open a secure, non-authenticated channel, which it then uses to procure a token string, which it then uses to create call credentials with the grpc.composite_channel_credentials() function:
channel = grpc.secure_channel(url_server_address, ssl_creds)
stub = gateway.GatewayStub(channel)
# Acquire access token via password authentication
pw_cmd = gateway.PasswordAuthenticateCmd(account_name=url.username, password=url.password)
auth_rsp = stub.PasswordAuthenticate(pw_cmd)
# Open a secure, authenticated channel
auth_creds = grpc.access_token_call_credentials(auth_rsp.access_token)
composite_creds = grpc.composite_channel_credentials(ssl_creds, auth_creds)
channel = grpc.secure_channel(url_server_address, composite_creds)
stub = gateway.GatewayStub(channel)
In c#, I have been able to compile the protocol buffer definitions, and connect with the generated client to successfully acquire the access token:
SslCredentials secureChannel = new SslCredentials(File.ReadAllText(SSLCertificatePath));
Channel channel = new Channel(ServerURL, PortNum, secureChannel);
var client = new GrpcClient(new Grpc.Gateway.GatewayClient(channel));
var response = client.client.PasswordAuthenticate(new PasswordAuthenticateCmd() { AccountName = UserName, Password = UserPassword });
Console.WriteLine(response.AccessToken);
From here, however, I can't find the c# analog to the grpc.composite_channel_credentials() function to take the SslCredentials and the access token string to create combined credentials.
None of the examples here https://grpc.io/docs/guides/auth.html here use a token string, and I haven't been able to find any other examples out there.

What you're looking for is:
https://github.com/grpc/grpc/blob/c5311260fd923079637f5d43bd410ba6de740443/src/csharp/Grpc.Core/CallCredentials.cs#L49 and https://github.com/grpc/grpc/blob/c5311260fd923079637f5d43bd410ba6de740443/src/csharp/Grpc.Core/ChannelCredentials.cs#L67.
Feel free to also look at:
https://github.com/grpc/grpc/blob/c5311260fd923079637f5d43bd410ba6de740443/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs#L58

I solved my problem using CallCredentials.FromInterceptor().
The grpc.access_token_call_credentials() python call adds an authorization entry to the metadata, and sets its value to "Bearer " + AccessToken, so I just had to do the same:
SslCredentials secureCredentials = new SslCredentials(File.ReadAllText(SSLCertificatePath));
Channel secureChannel = new Channel(ServerURL, PortNum, secureCredentials);
var client = new GrpcClient(new Grpc.Gateway.GatewayClient(secureChannel));
var response = client.client.PasswordAuthenticate(new PasswordAuthenticateCmd() { AccountName = UserName, Password = UserPassword });
var accessTokenCredentials = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) =>
{
metadata.Add("authorization", "Bearer " + passwordResponse.AccessToken);
return TaskUtils.CompletedTask;
}));
var authenticatedCredentials = ChannelCredentials.Create(secureCredentials, accessTokenCredentials);
Channel authenticatedChannel = new Channel(hostURL, hostPort, authenticatedCredentials);
As Jan pointed out in his answer, there is a function in the Grpc.Auth namespace that does the same thing as the function that I wrote: https://github.com/grpc/grpc/blob/c5311260fd923079637f5d43bd410ba6de740443/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs#L58

Related

Awssdk works on .net dotnetcore (IAM and GatewayAPI) but throws Amazon.CognitoIdentity.Model.NotAuthorizedException on Xamarin Android APP

I have a problem with Awssdk lib from Amazon that I can't understand.
I made an easy Class to authorized and obtain resources from Amazon.
It uses the configuration from user sessionConfig: clientId, identitypoolId,userpoolId, username, password, secret.
And also the request config (signRequest) host, absolutpath, method, region.
var client = AmazonClient(sessionConfig, requestconfig);
With this I can easyly
client.GetClientTokens();
That makes a call to CognitoAuth userpools:
var cred = new CognitoAWSCredentials(_sessionConfig.IdentityPoolId,` RegionEndpoint.EUCentral1);
var provider = new AmazonCognitoIdentityProviderClient(cred, RegionEndpoint.EUCentral1);
CognitoUserPool userPool = new CognitoUserPool(_sessionConfig.UserPoolId, _sessionConfig.ClientId, provider);
CognitoUser user = new CognitoUser(_sessionConfig.UserPoolId, _sessionConfig.ClientId, userPool, provider, _sessionConfig.Secret, _sessionConfig.UserName);
var authRequest = new InitiateSrpAuthRequest()
{
Password = _sessionConfig.Password
};
AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
Then I just call
client.GetApiResource(absolutpath);
And I can get with this auth info the resource from the api.
_requestConfig.AbsolutePath = absolutePath;
//Signmethod from Amazon
GetSignedRequest();
var responses = _webRequest.GetResponse();
var result = responses.GetResponseStream();
var data = string.Empty;
using (var sr = new StreamReader(result))
{
data = sr.ReadToEnd();
}
return data;
This code works like a charm on my dotnetcore console app, I become tokens access data and user or other api resources.
When I want to use it on a Xamarin.Android solution.
I become, when trying to get the credentials:
user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
Amazon.CognitoIdentity.Model.NotAuthorizedException: Access to
Identity 'eu-central-1:xxxxxxxxxxxxxxxxxxxxx' is forbidden.
System.Net.HttpStatusCode.BadRequest
errorCode "NotAuthorizedException"
The only thing I could see it is different is the UserAgent from provider config:
console program:
aws-sdk-dotnet-coreclr/3.3.11.22 aws-sdk-dotnet-core/3.3.29.12 .NET_Core/4.6.26606.02 OS/Microsoft_Windows_10.0.14393
Xamarin.Android app:
aws-sdk-dotnet-pcl/3.3.4.3 aws-sdk-dotnet-core/3.3.29.13 Mono/5.10.1(tarball) OS/ANDROID_7.0 PCL/Xamarin.Android
Console works xamarin throw this exception. Any ideas?

DocuSign API and DocumentPDFs docPDFs = apiService.RequestDocumentPDFs(envelopeID);

I am using the code below to connect to DocuSign API.
WHAT AM I doing wrong, I keep getting Username and Password not correct when they are!
String auth = "<DocuSignCredentials><Username>john.connolly#lechase.com</Username><Password>password</Password><IntegratorKey>20be051c-4c25-46c1-b0f1-1f10575a2e40</IntegratorKey></DocuSignCredentials>";
DSAPIServiceSoapClient client = new DSAPIServiceSoapClient("DSAPIServiceSoap");
using (System.ServiceModel.OperationContextScope scope = new System.ServiceModel.OperationContextScope(client.InnerChannel))
{
System.ServiceModel.Channels.HttpRequestMessageProperty httpRequestProperty = new System.ServiceModel.Channels.HttpRequestMessageProperty();
httpRequestProperty.Headers.Add("X-DocuSign-Authentication", auth);
System.ServiceModel.OperationContext.Current.OutgoingMessageProperties[System.ServiceModel.Channels.HttpRequestMessageProperty.Name] = httpRequestProperty;
EnvelopeStatus status = client.RequestStatusEx("12d46951-1f1c-48cd-9a28-e51685d67ccd");
Console.Out.WriteLine("Subject: " + status.Subject);
}
Since you use the (Legacy Header Authentication uses the X-DocuSign-Authentication header):
Use the Authentication: login method
to retrieve the account number and the baseUrl for the account.
The url for the login method is www.docusign.net for production and
demo.docusign.net for the developer sandbox. The baseUrl field is
part of the loginAccount object. See the docs and the loginAccount
object
The baseUrl for the selected account, in production, will start with na1, na2, na3, eu1, or something else. Use the baseUrl that is
returned to create the basePath (see the next step.) Use the
basePath for all of your subsequent API calls.
As returned by login method, the baseUrl includes the API version and account id. Split the string to obtain the basePath, just the
server name and api name. Eg, you will receive
https://na1.docusign.net/restapi/v2/accounts/123123123. You want
just https://na1.docusign.net/restapi
Instantiate the SDK using the basePath. Eg ApiClient apiClient = new ApiClient(basePath);
Set the authentication header as shown in the examples by using Configuration.Default.AddDefaultHeader Ref.
Sample Code: Try a verbatim string for your auth string.
string auth = #"<DocuSignCredentials>
<Username>john.connolly#lechase.com</Username>
<Password>S3cre+p455w0Rd</Password>
<IntegratorKey>20be051c-4c25-46c1-b0f1-1f10575a2e40</IntegratorKey>
</DocuSignCredentials>";
DSAPIServiceSoapClient apiService = new DSAPIServiceSoapClient();
using (var scope = new System.ServiceModel.OperationContextScope(apiService.InnerChannel))
{
var httpRequestProperty = new System.ServiceModel.Channels.HttpRequestMessageProperty();
httpRequestProperty.Headers.Add("X-DocuSign-Authentication", auth);
System.ServiceModel.OperationContext.Current.OutgoingMessageProperties[System.ServiceModel.Channels.HttpRequestMessageProperty.Name] = httpRequestProperty;
EnvelopeStatus envStatus = apiService.CreateAndSendEnvelope(envelope);
return envStatus.EnvelopeID;
}

How to create a new Microsoft Azure HybridConnection via code?

I am using HybridConnectionNamespace and create multiple HybridConnections via Azure portal. The question is quite simple. How can I create it programmatically (Azure SDK, PowerShell scripts, etc.)?
According to this article, there are currently two different ways to create a relay namespace.
Azure portal and Azure Resource Manager templates
If you want to create it programmatically, I suggest you could use azure rest api to send the deployment templates by codes.
More details, you could refer to this article and codes:
Notice: If you want to use rest api to send request to azure, you need firstly create an Azure Active Directory application and service principal. After you generate the service principal, you could get the applicationid,access key and talentid. More details, you could refer to this article.
Rest Body(json.txt):
Notice: You need change the parameters' name and location value.
{"properties":{"mode":"incremental","debugSetting":{"detailLevel":"RequestContent, ResponseContent"},"parameters":{"name":{"value":"yourrelayname"},"location":{"value":"location"}},"template":{"$schema":"http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#","contentVersion":"1.0.0.0","parameters":{"name":{"type":"string"},"location":{"type":"string"}},"resources":[{"apiVersion":"2016-07-01","name":"[parameters('name')]","location":"[parameters('location')]","type":"Microsoft.Relay/namespaces","properties":{"namespaceType":"Relay"}}]}}}
Code:
string body = File.ReadAllText(#"D:\json.txt");
// Display the file contents to the console. Variable text is a string.
string tenantId = "tenantId";
string clientId = "clientId(applicationid)";
string clientSecret = "applicationSecret";
string subscription = "subscriptionId";
string resourcegroup = "Youresourcegroup";
string authContextURL = "https://login.windows.net/" + tenantId;
var authenticationContext = new AuthenticationContext(authContextURL);
var credential = new ClientCredential(clientId, clientSecret);
var result = authenticationContext.AcquireTokenAsync(resource: "https://management.azure.com/", clientCredential: credential).Result;
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(string.Format("https://management.azure.com/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Resources/deployments/Microsoft.Relay?api-version=2016-07-01", subscription, resourcegroup));
request.Method = "PUT";
request.Headers["Authorization"] = "Bearer " + token;
request.ContentType = "application/json";
try
{
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(body);
streamWriter.Flush();
streamWriter.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
//Get the response
var httpResponse = (HttpWebResponse)request.GetResponse();
Console.WriteLine(httpResponse.StatusCode);
Console.ReadLine();
Result:
Use PowerShell CmdLets | Hybrid Connection Manager:
Add-HybridConnection
Update-HybridConnection
Remove-HybridConnection
Get-HybridConnection
Set-HybridConnectionManagerConfiguration
https://msdn.microsoft.com/en-us/library/azure/dn789178.aspx
GoodLuck

Consume WSDL that requires action level authorization in C#

I'm attempting to consume a 3rd party WSDL. I have added it as a service reference. I initalize the client and query paramaters like this:
var ltRequest = new SearchEmailAddressStatus
{
EmailAddress = emailAddressList.ToArray()
};
var ltClient = new CommunicationPreferenceServiceClient
{
ClientCredentials =
{
UserName =
{
UserName = ltProperties.CompanyCredential.UserName,
Password = ltProperties.CompanyCredential.Password
}
}
};
var ltResponse = ltClient.searchEmailAddressStatusWS(ltRequest);
After watching the packets in Fiddler, I've noticed the Auth header is never sent to the server. Is there any way to manually insert an authorization header in my request?
Okay, after a lot of digging I found the answer. After declaring the client, I used the following code:
using (var scope = new OperationContextScope(ltClient.InnerChannel))
{
var reqProperty = new HttpRequestMessageProperty();
reqProperty.Headers[HttpRequestHeader.Authorization] = "Basic "
+ Convert.ToBase64String(Encoding.ASCII.GetBytes(
ltClient.ClientCredentials.UserName.UserName + ":" +
ltClient.ClientCredentials.UserName.Password));
OperationContext.Current
.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = reqProperty;
var ltResponse = ltClient.searchEmailAddressStatusWS(ltRequest);
}
I believe this is the least-dirty means of getting a customized header inside wsdl request. If someone has a better method, I'd love to hear it.

What is the verifier in DotNetOpenAuth's DesktopConsumer ProcessUserAuthorization?

I am new to DotNetOpenAuth and I can't find what value to use as the verifier in ProcessUserAuthorization.
What I want to achieve is to log in with my user credentials into an application (called UserVoice) that uses OAuth. Here's what my code looks like:
string requestToken;
var authorizeUri = consumer.RequestUserAuthorization(new Dictionary<string, string>(), null, out requestToken).AbsoluteUri;
var verifier = "???";
var accessToken = consumer.ProcessUserAuthorization(requestToken, verifier).AccessToken;
consumer.PrepareAuthorizedRequest(endpoint, accessToken, data).GetResponse();
I tried to use my username, my password, my consumer key, my consumer secret, but nothing seems to work. Does someone know which value I should use as the verifier?
Thanks
I finally found a way to log in to UserVoice with DotNetOpenAuth. I think UserVoice's implementation of OAuth wasn't standard, but I was able to do it during this:
var consumer = new DesktopConsumer(this.GetInitialServiceDescription(), this._manager)
string requestToken;
consumer.RequestUserAuthorization(null, null, out requestToken);
// get authentication token
var extraParameters = new Dictionary<string, string>
{
{ "email", this._email },
{ "password", this._password },
{ "request_token", requestToken },
};
consumer = new DesktopConsumer(this.GetSecondaryServiceDescription(), this._manager);
consumer.RequestUserAuthorization(extraParameters, null, out requestToken);
Where GetInitialServiceDescription returns the good request description, and GetSecondaryServiceDescription is a hacked version and returns the authorize endpoint in place of the request token endpoint. The "request_token" returned this way (which is not really a normal request_token from my understanding of OAuth) can then be used as an access token for PrepareAuthorizedRequest.
The verifier is the code that UserVoice would display onscreen after the user has said they want to authorize your app. The user must copy and paste this verifier code from the web site back into your application's GUI, so that it can then pass it into the ProcessUserAuthorization method.
This is only required in OAuth 1.0a (not 1.0), and is there to mitigate certain exploitable attacks that were discovered in 1.0. In your ServiceProviderDescription be sure you specify that the service is a 1.0a version (if in fact Uservoice supports that) so that DNOA will communicate to Uservoice that it should create a verifier code.
Incidentally, various tricks including scanning process titles or hosting the browser within your own app can eliminate the manual user copying the verify code step by having your app automatically copy it for him.
The verifier is also used when the Authorization is done via WebAPI and you do not have a redirect displayed in a browser. In this you just send your AuthentificationRequest via code and get the verifier as a json-string without any user interaction.
In this case the process (for OAuth 1.0) looks as follows:
public void AccessAPI ()
{
InMemoryOAuthTokenManager tokenManager = InMemoryOAuthTokenManager(YOUR_CLIENT_KEY, YOUR_CLIENT_SECRET);
var consumer = new DesktopConsumer(GetAuthServerDescription(), tokenManager);
// Get Request token
string requestToken;
var parameters = new Dictionary<string, string>();
parameters["email"] = "foo";
parameters["password"] = "bar";
Uri authorizationUrl = consumer.RequestUserAuthorization(null, parameters, out requestToken);
// Authorize and get a verifier (No OAuth Header necessary for the API I wanted to access)
var request = WebRequest.Create(authorizationUrl) as HttpWebRequest;
request.Method = "Get";
request.Accept = "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2";
var response = request.GetResponse() as HttpWebResponse;
string verifier = new StreamReader(response.GetResponseStream()).ReadToEnd().Split('=')[1]; //Irgendwie will Json nicht parsen
// Use verifier to get the final AccessToken
AuthorizedTokenResponse authorizationResponse = consumer.ProcessUserAuthorization(requestToken, verifier);
string accessToken = authorizationResponse.AccessToken;
// Access Ressources
HttpDeliveryMethods resourceHttpMethod = HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest;
var resourceEndpoint = new MessageReceivingEndpoint("https://api.discovergy.com/public/v1/meters", resourceHttpMethod);
using (IncomingWebResponse resourceResponse = consumer.PrepareAuthorizedRequestAndSend(resourceEndpoint, accessToken))
{
string result = resourceResponse.GetResponseReader().ReadToEnd();
dynamic content = JObject.Parse(result);
}
}
private ServiceProviderDescription GetAuthServerDescription()
{
var authServerDescription = new ServiceProviderDescription();
authServerDescription.RequestTokenEndpoint = new MessageReceivingEndpoint(YOUR_REQUEST_ENDPOINT, HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest);
authServerDescription.UserAuthorizationEndpoint = new MessageReceivingEndpoint(YOUR_AUTHORIZATION_ENDPOINT, HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest);
authServerDescription.AccessTokenEndpoint = new MessageReceivingEndpoint(YOUR_TOKEN_ENDPOINT, HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest);
authServerDescription.ProtocolVersion = ProtocolVersion.V10;
authServerDescription.TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() };
return authServerDescription;
}

Categories