It seems most of the WIF information out there is useful for enabling federated authentication across entire applications. I'm interested in using the API to create SAML authentication requests and receive/interpret the SAML responses.
I found the following post on SO Reading SAML Attributes from SAML Token that gets me going in the right direction in regards to receiving and interpreting SAML responses. Can anyone give me more information on how I might use the API to create SAML requests?
Any more info (reading material, videos, etc) on the API in general would be greatly appreciated.
Here's a little example form one of our samples that shows how to programatically create a request for a (SAML) Security Token to an STS:
private static SecurityToken GetSamlToken(string realm, string stsEndpoint, ClientCredentials clientCredentials)
{
using (var factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress(new Uri(stsEndpoint))))
{
factory.Credentials.UserName.UserName = clientCredentials.UserName.UserName;
factory.Credentials.UserName.Password = clientCredentials.UserName.Password;
factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
factory.TrustVersion = TrustVersion.WSTrust13;
WSTrustChannel channel = null;
try
{
var rst = new RequestSecurityToken
{
RequestType = WSTrust13Constants.RequestTypes.Issue,
AppliesTo = new EndpointAddress(realm),
KeyType = KeyTypes.Bearer,
};
channel = (WSTrustChannel)factory.CreateChannel();
return channel.Issue(rst);
}
finally
{
if (channel != null)
{
channel.Abort();
}
factory.Abort();
}
}
Since no one else has answered, here's an article from the inimitable Michelle Bustamante:
http://www.devproconnections.com/article/federated-security/Generate-SAML-Tokens-Using-Windows-Identity-Foundation.aspx
Related
I would like to subscript to a Salesforce platform event. I am trying to create a client in C#/.NET for a Salesforce Pub/Sub API. There are examples in other languages but not in .NET : https://github.com/developerforce/pub-sub-api
I am using the Grpc.Net.Client nuget packages.
var topicName = "/event/SomeEvent__e";
var pubSubEndpoint = "https://api.pubsub.salesforce.com:7443";
var accessToken = "xxxx";
var organisationId = "xxxx";
var instanceUrl = "https://xxxxx.sandbox.my.salesforce.com";
var credentials = CallCredentials.FromInterceptor((c, m) =>
{
m.Add("accesstoken", accessToken);
m.Add("instanceurl", instanceUrl);
m.Add("tenantid", organisationId);
return Task.CompletedTask;
});
var options = new GrpcChannelOptions
{
Credentials = ChannelCredentials.Create(new SslCredentials(), credentials)
};
var channel = GrpcChannel.ForAddress(pubSubEndpoint, options);
var client = new PubSub.PubSubClient(channel);
var topicRequest = new TopicRequest()
{
TopicName = topicName
};
var topic = client.GetTopic(topicRequest);
I know my credentials are correct because I can use postman to hit the oauth2 endpoint and get a valid access token. But when I try and call a client method like client.GetTopic, then I get the following error.
Status(StatusCode="PermissionDenied", Detail="An error occurred while getting the metadata for org CORE/prod/00DN0000000c8Hk and topic /event/SomeEvent__e. Ensure the credentials and topic name are correct. rpcId: 21d854fb-17dc-4778-9524-6264bd1a920d")
Am I setting up the credentials object wrong? I cannot find any example of subscribing to a Salesforce Pub/Sub in .NET.
Im newbie in C#, I have been asked to implement the OpenID login with provided username and password and get the bearer token.
We achieved this in Java code snipped is as below.(don't know how do same in C#)
public AccessTokenResponse getToken() throws IOException, ParseException, Exception {
StringBuilder query = new StringBuilder("");
ClientCredentialsGrant clientAuth = new ClientCredentialsGrant();
Map<String, String> parameters = clientAuth.toParameters();
for (String key : parameters.keySet()) {
query.append(key).append("=").append(parameters.get(key)).append("&");
}
ClientID clientID = new ClientID(config.getProperty(ConfigConstants.USERNAME));
Secret secret = new Secret(config.getPassword());
ClientSecretBasic csb = new ClientSecretBasic(clientID, secret);
//logger.info("URL:" + this.getOpenIDMetadata(config.getProperty(ConfigConstants.DOMAIN)).getTokenEndpointURI().toString());
TokenRequest tokenRequest = new TokenRequest(this.getOpenIDMetadata(config.getProperty(ConfigConstants.DOMAIN)).getTokenEndpointURI(), csb, clientAuth);
HTTPRequest request = tokenRequest.toHTTPRequest();
HTTPResponse httpResponse = request.send();
accessToken = AccessTokenResponse.parse(httpResponse);
return accessToken;
}
We have a server which is an openid provider and this is how get the OIDCProviderMetadata
private OIDCProviderMetadata getOpenIDMetadata(String domain) throws Exception {
if (this.metadata == null) {
String confURL = this.serverURL+ config.getIDP() + domain + "/authn/.well-known/openid-configuration";
HTTPRequest configRequest = new HTTPRequest(HTTPRequest.Method.GET, new URL(confURL));
HTTPResponse configResponse = configRequest.send();
metadata = OIDCProviderMetadata.parse(configResponse.getContent());
}
return metadata;
}
Question is how to implement same thing in C#?
I did some research around this, found there is/are official OpendID implementation in C# i.e.
https://github.com/IdentityModel/IdentityModel.OidcClient2
but did not find any samples which will help me to implement likewise in Java implementation i have. All examples demonstrate do openid login in browser or mobiles devices i don't want that, I want similar implementation as we have in Java(above).
Any help would be appreciated or code snipped would be more helpful.
I'm writing client using WCF for demo settings provided by PingFederate in the similar way as described in this post (Getting a Token from PingFederate using WIF).
My problem is that on the second step I need to exchange SAML token to lightweight SSO token on SP.
I'm getting exception while serialization of response from the SP
ID3135: The element 'TokenType' with namespace 'http://docs.oasis-open.org/ws-sx/ws-trust/200512' has value 'BASE64BINARY' which is not an absolute URI.
as I understand WS2007FederationHttpBinding can't handle that type of tokens.
I'm looking for explanation how such scenario should be handled.
The the client code is as following (after getting SAML token from IDP)
var binding = new WS2007FederationHttpBinding();
binding.Security.Mode = WSFederationHttpSecurityMode.TransportWithMessageCredential;
binding.Security.Message.IssuedKeyType = SecurityKeyType.BearerKey;
binding.Security.Message.EstablishSecurityContext = false;
var factory = new WSTrustChannelFactory(binding, new EndpointAddress(SP_EndPoint));
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.SupportInteractive = false;
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
//AppliesTo = new EndpointReference(#"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"),
};
RequestSecurityTokenResponse rstr;
var channel = factory.CreateChannelWithIssuedToken(idpToken);
SecurityToken spToken = channel.Issue(rst, out rstr);
return spToken;
I'm playing with OneDrive SDK 1.1.15.0:
try
{
AppConfig appConfig = new AppConfig
{
MicrosoftAccountAppId = oneDriveClientID, //something like 00000000123456AB
MicrosoftAccountClientSecret = oneDriveClientSecret, //something like 3vx[...]1sJ
MicrosoftAccountReturnUrl = "https://localhost/return",
MicrosoftAccountScopes = new string[] { "wl.signin", "wl.offline_access", "onedrive.readonly" }
};
OneDriveClient oneDriveClient = new OneDriveClient(appConfig);
AccountSession accountSession = await oneDriveClient.AuthenticateAsync();
//more code
await oneDriveClient.SignOutAsync();
}
catch (Exception ex)
{
throw ex;
}
My problem is in line:
AccountSession accountSession = await oneDriveClient.AuthenticateAsync();
that throws the following exception:
Microsoft.OneDrive.Sdk.OneDriveException, AuthenticationFailure: Failed to retrieve a valid authentication token for the user.
Any ideas?
Thank you in advance!
UPDATE
After reading comment from ginach (thank you!), I update my code. Some arguments to underline:
I want to access OneDrive from an Azure worker Role, so no authentication windows or something like that.
I upload the Microsoft.OneDrive SDK to 1.1.20 version.
I already registered my application to the OneDrive dev portal.
My actual code is:
try
{
MicrosoftAccountServiceInfo serviceInfo = new MicrosoftAccountServiceInfo();
serviceInfo.AppId = oneDriveClientID; //something like: 00000000ABCDEFGH
serviceInfo.ClientSecret = oneDriveClientSecret; //something like: 3vx[...]1sJ
serviceInfo.ReturnUrl = oneDriveReturnUrl; //something like: https://localhost/return
serviceInfo.Scopes = oneDriveAccountScopes; //something like new string[] { "wl.signin", "wl.offline_access", "onedrive.readonly" }
MicrosoftAccountAuthenticationProvider authenticationProvider = new MicrosoftAccountAuthenticationProvider(serviceInfo);
OneDriveClient oneDriveClient = await OneDriveClient.GetAuthenticatedMicrosoftAccountClient(oneDriveClientID, oneDriveReturnUrl, oneDriveAccountScopes, authenticationProvider);
//more code
await oneDriveClient.SignOutAsync();
}
catch (OneDriveException odex)
{
throw odex;
}
catch (Exception ex)
{
throw ex;
}
I obtain again and again (in OneDriveClient.GetAuthenticatedMicrosoftAccountClient method) a OneDriveException stating (Error property): AuthenticationFailure - Failed to retrieve a valid authentication token for the user.
Any suggestion?
Thank you.
UPDATE 2
OK, I'm trying a new approach. Using RestSharp I try to login to OneDrive with that code:
string clientId = "00[...]00";
string scopes = "wl.signin, wl.offline_access, onedrive.readonly";
string responseType = "code";
string redirectUri = "https://login.live.com/oauth20_desktop.srf";
RestClient client = new RestClient("https://login.live.com");
RestRequest request = new RestRequest();
request.Method = Method.GET;
request.Resource = "oauth20_authorize.srf";
request.AddQueryParameter("client_id", clientId);
request.AddQueryParameter("scope", scopes);
request.AddQueryParameter("response_type", responseType);
request.AddQueryParameter("redirect_uri", redirectUri);
IRestResponse response = client.Execute(request);
string content = response.Content;
I check the request with Fiddler and what I'm sending is:
https://login.live.com/oauth20_authorize.srf?client_id=00[...]00&scope=wl.signin%20wl.offline_access%20onedrive.readonly&response_type=code&redirect_uri=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf
But OneDrive server answers my with:
Microsoft account requires JavaScript to sign in. This web browser either does not support JavaScript, or scripts are being blocked. To find out whether your browser supports JavaScript, or to allow scripts, see the browser's online help.
So I try the request in a browser and OneDrive server redirects me to the authorization page:
Now the question is: is there any workaround to skip the manual authorization?
Thank you,
Attilio
The client requires an authentication provider to be able to retrieve authentication tokens. There are a few ways to do this depending on your current platform.
Create your own IAuthenticationProvider implementation. The authentication provider is responsible for setting the Authentication header on requests. Here's how you would create a client instance with a custom authentication provider:
var client = new OneDriveClient(appConfig, serviceInfoProvider: new
ServiceInfoProvider(new CustomAuthenticationProvider()));
Use one of the various default authentication implementations. Take a look at the SDK authentication documentation for the available options and examples.
If you have a refresh token and only want to do the silent authentication flow you can use OneDriveClient.GetSilentlyAuthenticatedMicrosoftAccountClient. Here's an example:
var client = await OneDriveClient.GetSilentlyAuthenticatedMicrosoftAccountClient(clientId, returnUrl, scopes, refreshToken);
I'm trying to use OAuth for authentication for the FreshBooks API from my ASP.NET MVC C# app. Here is what I have so far:
I'm using DotNetOpenAuth here is the code I have in my controller action
if (TokenManager != null)
{
ServiceProviderDescription provider = new ServiceProviderDescription();
provider.ProtocolVersion = ProtocolVersion.V10a;
provider.AccessTokenEndpoint = new MessageReceivingEndpoint ("https://myfbid.freshbooks.com/oauth/oauth_access.php", DotNetOpenAuth.Messaging.HttpDeliveryMethods.PostRequest);
provider.RequestTokenEndpoint = new DotNetOpenAuth.Messaging.MessageReceivingEndpoint("https://myfbid.freshbooks.com/oauth/oauth_request.php", DotNetOpenAuth.Messaging.HttpDeliveryMethods.PostRequest);
provider.UserAuthorizationEndpoint = new DotNetOpenAuth.Messaging.MessageReceivingEndpoint("https://myfbid.freshbooks.com/oauth/oauth_authorize.php", DotNetOpenAuth.Messaging.HttpDeliveryMethods.GetRequest);
provider.TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() };
var consumer = new WebConsumer(provider, TokenManager);
var response = consumer.ProcessUserAuthorization();
if (response != null)
{
this.AccessToken = response.AccessToken;
}
else
{
// we need to request authorization
consumer.Channel.Send(consumer.PrepareRequestUserAuthorization(
new Uri("http://localhost:9876/home/testoauth/"), null, null));
}
}
The TokenManager is the same class that is provided with the DotNetOpenAuth sample, I've set my consumer secret that FreshBooks gave me.
On the consumer.Channel.Send(consumer.PrepareRequestUserAuthorization(...)) I've got the following exception:
"The remote server returned an error: (400) Bad Request.".
Am I doing this correctly? Based on FreshBooks documentation and DotNetOpenAuth samples that should work correctly.
Is there a simpler way to authenticate with OAuth, as DotNetOpenAuth is a bit huge for simply using OAuth authentication?
if you want to use DotNetOpenAuth you need to make sure that:
you use signature method "PLAINTEXT"
and use PlaintextSigningBindingElement as TamperProtectionElements
something like this works for me:
public static readonly ServiceProviderDescription ServiceDescription = new ServiceProviderDescription
{
ProtocolVersion = ProtocolVersion.V10a,
RequestTokenEndpoint = new MessageReceivingEndpoint(oAuthBase + "/oauth_request.php", HttpDeliveryMethods.PostRequest),
UserAuthorizationEndpoint = new MessageReceivingEndpoint(oAuthBase + "/oauth_authorize.php", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
AccessTokenEndpoint = new MessageReceivingEndpoint(oAuthBase + "/oauth_access.php", HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new PlaintextSigningBindingElement() }
};
public static void RequestAuthorization(WebConsumer consumer)
{
if (consumer == null)
{
throw new ArgumentNullException("consumer");
}
var extraParameters = new Dictionary<string, string> {
{ "oauth_signature_method", "PLAINTEXT" },
};
Uri callback = Util.GetCallbackUrlFromContext();
var request = consumer.PrepareRequestUserAuthorization(callback, extraParameters, null);
consumer.Channel.Send(request);
}
You could try using my open source OAuth Library. It's extremely simple to use and get going. I have a sample project that's available in the download that connects to Google, Twitter, Yahoo and Vimeo. I've intentionally kept the code very simple so it's easy to understand.
OAuth C# Library
I've not used FreshBooks, but it should be a simple matter of changing the url for one of the providers in the sample application and of course setting up provider specific keys etc.