C# ADFS SAML token with Windows Auth / Current logged in user - c#

How do I generate a SAML token without using credentials again?
Scenario: I am trying to send a SAML token to SAP web service. Since multiple users will be using this application I do not want to ask them for credentials but instead get them from current machine windows credentials and generate a SAML token.
This is what is currently being used in my code.
factory.Credentials.UserName.UserName = "bob";
factory.Credentials.UserName.Password = "abc!123";
// create token request
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Symmetric,
AppliesTo = new EndpointReference(_serviceAddress.AbsoluteUri)
};

I use this method in my code to pass through the credentials of the logged in user to our ADFS server for single-sign in to O365 from the applications I write; you might be able to adapt the code to suit your purposes:
private GenericXmlSecurityToken NewGetAdfsSamlTokenWinAuth()
{
try
{
WS2007HttpBinding binding = new WS2007HttpBinding(SecurityMode.Transport);
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
WSTrustChannelFactory factory = new WSTrustChannelFactory((binding), new EndpointAddress(this.adfsIntegratedAuthUrl));
factory.TrustVersion = TrustVersion.WSTrustFeb2005;
factory.Credentials.SupportInteractive = false;
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointReference("urn:federation:MicrosoftOnline"),
KeyType = KeyTypes.Bearer
};
IWSTrustChannelContract channel = factory.CreateChannel();
return channel.Issue(rst) as GenericXmlSecurityToken;
}
catch (Exception ex)
{
// Do something with the exception
}
return null;
}
This will return a GenericXmlSecurityToken which has a TokenXml.OuterXml property that contains the SAML assertion.

Related

Retrieving SAML token for a relying party trust using windows pass-through authentication

I'm attempting to determine a way for an application to retrieve a SAML token to access a relying party trust on behalf of the current context of the application (as a user).
The common recommendation is to retrieve a SAML token using WSTrustChannelFactory but with supplying a username and password. I would like to not do this so it is seamless to the user. I feel like ADFS should support SSO authentication (using passthrough windows auth) for this request. Is this possible?
Here is the typical recommended code that requires credentials:
public SecurityToken GetSamlToken()
{
using (var factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress(new Uri("https://serv/adfs/services/trust/13/usernamemixed"))))
{
factory.Credentials.UserName.UserName = "username";
factory.Credentials.UserName.Password = "password";
factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
factory.TrustVersion = TrustVersion.WSTrust13;
WSTrustChannel channel = null;
try
{
string KeyType;
var rst = new RequestSecurityToken
{
RequestType = WSTrust13Constants.RequestTypes.Issue,
AppliesTo = new EndpointAddress("net.tcp://localhost:xxxx/Service1/mex"),
KeyType = Microsoft.IdentityModel.Protocols.WSTrust.WSTrust13Constants.KeyTypes.Bearer,
};
channel = (WSTrustChannel)factory.CreateChannel();
return channel.Issue(rst);
}
finally
{
if (channel != null)
{
channel.Abort();
}
factory.Abort();
}
}
}
Thank you for your help!

How to add SAML token to SOAP Request in C#

I try to call a SOAP service by authenticating myself with a SAML token.
First I get a SAML token for the target by calling the ADFS:
var stsEndpoint = "https://ADFS.EXAMPLE/adfs/services/trust/13/kerberosmixed";
var reliantPartyUri = "http://reliant-party.com";
var binding = new CustomBinding();
var ssbe = SecurityBindingElement.CreateKerberosOverTransportBindingElement();
ssbe.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic128;
ssbe.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
binding.Elements.Add(ssbe);
binding.Elements.Add(new TextMessageEncodingBindingElement());
binding.Elements.Add(new HttpsTransportBindingElement());
var factory = new WSTrustChannelFactory(binding, new EndpointAddress(stsEndpoint));
factory.TrustVersion = TrustVersion.WSTrust13;
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointReference(reliantPartyUri)
};
var channel = factory.CreateChannel();
var token = channel.Issue(rst);
Now I want to use the SAML token to call a secured SOAP webservice. How is it possible to add the token? I've tried the following without success (the soap request does not contain any token):
//Service was created by an imported WSDL File - Methods and Types renamed for StackOverflow
var request = new Service.WsdlCreatedRequest();
[...]
var wsdlClient = new Service.WsdlCreatedService("HTTPS_Port");
var wsdlChannel = wsdlClient.ChannelFactory.CreateChannelWithIssuedToken(token);
wsdlChannel.WsdlCreatedMethod(request);
Any idea how to use the token in the request?

How to obtain a JWT from ADFS (Windows server 2012R2) using a ClientAssertionCertificate in C#

I'm having trouble obtaining a JWT from ADFS (Windows server 2012R2) using a ClientAssertionCertificate.
It all works fine when I let the user authenticate with his username and password directly into the adfs - login window, but I don't want my application to show the ADFS - login window, because the users of my application won't know the credentials. My application actually IS the user (of an api) so I want to authenticate using a certificate. When i try doing that, I get the message "The authorization server does not support the requested grant_type. The authorization server only supports authorization_code or refresh_token as the grant type.
Does anyone know any workaround or other method to obtain a JWT from ADFS using a certificate? Thx a lot!
My application is a .Net 4.6.1 console application.
This is my code now:
var certPath = Path.Combine(GetCurrentDirectoryFromExecutingAssembly(), "mycertificate.pfx");
var certfile = File.OpenRead(certPath);
var certificateBytes = new byte[certfile.Length];
certfile.Read(certificateBytes, 0, (int)certfile.Length);
var cert = new X509Certificate2(
certificateBytes,
"mypassword",
X509KeyStorageFlags.Exportable |
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet);
var certificate = new ClientAssertionCertificate("myclientid", cert);
AuthenticationContext context = new AuthenticationContext("https://sts.example.com/adfs",false);
AuthenticationResult authenticationResult = await context.AcquireTokenAsync("http://example.com/api", certificate);
var token = authenticationResult.AccessToken;
Have you tried using a WSTrustChannelFactory with CertificateWSTrustBinding?
In the RequestSecurityToken you can specify in the TokenType that you want a JWT. The JWT you receive will be a base64 string that you need to decode.
public static async Task<string> GetAccessToken(string authority, string resource, string clientId)
{
var certPath = Path.Combine(GetCurrentDirectoryFromExecutingAssembly(), "mycertificate.pfx");
var certfile = File.OpenRead(certPath);
var certificateBytes = new byte[certfile.Length];
certfile.Read(certificateBytes, 0, (int)certfile.Length);
var cert = new X509Certificate2(
certificateBytes,
"PASSWORD",
X509KeyStorageFlags.Exportable |
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet);
var factory = new WSTrustChannelFactory(
new CertificateWSTrustBinding(
SecurityMode.TransportWithMessageCredential),
"https://example.com/adfs/services/trust/13/certificatemixed") {TrustVersion = TrustVersion.WSTrust13};
if (factory.Credentials != null)
factory.Credentials.ClientCertificate.Certificate = cert;
// create token request
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Bearer,
AppliesTo = new EndpointReference("http://example.com/api"),
KeySizeInBits = 0,
TokenType = "urn:ietf:params:oauth:token-type:jwt"
};
// request token and return
var genericXmlSecurityToken = factory.CreateChannel().Issue(rst) as GenericXmlSecurityToken;
return genericXmlSecurityToken != null
? Encoding.UTF8.GetString(Convert.FromBase64String(genericXmlSecurityToken.TokenXml.InnerXml))
: string.Empty;
}

C# Service Request

I stack on Apple GSX Api request in c# project. Everything is ok but I cannot get response from api.
Certificates done, Static IPs have whitelisted.
Return this error when i request to "https://gsxapiut.apple.com/gsx-ws/services/emea/asp"
{"An error occurred while making the HTTP request to
https://gsxapiut.apple.com/gsx-ws/services/emea/asp. This could be due
to the fact that the server certificate is not configured properly
with HTTP.SYS in the HTTPS case. This could also be caused by a
mismatch of the security binding between the client and the server."}
Request Function :
public void Authenticate()
{
try
{
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
EndpointAddress endpoint = new EndpointAddress("https://gsxapiut.apple.com/gsx-ws/services/emea/asp");
var sslCertFilename = "test.p12";
var sslCertPassword ="xxxxx";
GsxApi3.GsxWSEmeaAspPortClient service = new GsxApi3.GsxWSEmeaAspPortClient();
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
service.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(
sslCertFilename,
sslCertPassword, X509KeyStorageFlags.MachineKeySet);
var auth = new GsxApi3.authenticateRequestType()
{
languageCode = "EN",
serviceAccountNo = "xxxxxxxxx",
userId = "xxxxxxxxxxx",
userTimeZone = "CET"
};
var session = service.Authenticate(auth);
var userSessionId = new GsxApi3.gsxUserSessionType { userSessionId = session.userSessionId };
}
catch (Exception err)
{
}
}

How use AD FS token in console application

i have AD FS server, console app and simple web site wher i can sign in with my domain account.
In my console application i get token from STS. Now, I want log with him to web site (i want check token).
How should I use this token in WebClient, WebApiClient and WCF?
I tried Opened channel in WCF with this token and download page using WebClient but i get log page.
this token is inportant 2 weeks, how cann I cancel this token earlier?
this is my code to get token (works):
string userName = "login";
string password = "pass";
string adfsAdr = #"https://domain/adfs/services/trust/13/usernamemixed";
string webPage = #"https://MyAspNetAppAdrs.com";
var factory = new Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress(adfsAdr));
factory.TrustVersion = TrustVersion.WSTrust13;
if (_factory.Credentials != null)
{
factory.Credentials.UserName.UserName = userName;
factory.Credentials.UserName.Password = password;
}
var rst = new RequestSecurityToken
{
RequestType = WSTrust13Constants.RequestTypes.Issue,
AppliesTo = new EndpointAddress(webPage),
KeyType = WSTrust13Constants.KeyTypes.Bearer,
};
var channel = factory.CreateChannel();
SecurityToken token = channel.Issue(rst);

Categories

Resources