Unable to sign security tokens with certificate in WIF scenario - wcf

I'm trying to implement a custom STS for a WIF scenario I'm investigating, but it's failing. It's failing when trying to obtain the private key from the certificate used to sign the tokens. I create the STS with the following configuration:
var signingCert = new X509Certificate2(#"C:\<path>\MySigningCertificate.pfx");
var config
= new SecurityTokenServiceConfiguration()
{
DisableWsdl = true,
TokenIssuerName = "Tribold",
SecurityTokenService = typeof(TriboldSecurityTokenService),
SigningCredentials = new X509SigningCredentials(signingCert),
CertificateValidationMode = X509CertificateValidationMode.Custom,
CertificateValidator = new CertificateValidator()
};
However, with WCF diagnostic logging configured, I get the following message in the Service Trace Viewer:
The private key is not present in the X.509 certificate.
This appears to be logged as the code comes out of my custom STS (i.e., after calling GetOutputClaimsIdentity(...) on my custom STS class, and therefore I can only assume that it's now trying to sign the issued security token and failing because it can't obtain a private key to do so.
The private key appears to be present on the loaded certificate:
Debug.Assert(signingCert.HasPrivateKey == true);
but it fails later on. I'm having no luck resolving this, please help!

It looks like thread "cant use .pfx file for X.509 certificates" in the Geneva (= AD FS 2.0) forums covers the same problem which you report. So the resolution reported there might work, which is "specifying the X509KeyStorageFlags.PersistKeySet flag when initiating the X509Certificate2 object".

I'd be surprised if you didn't have to specify a password when opening a PFX file. X509Certificate2 has overloads that take a password in the form of a string or a SecureString.

Related

Adding Certificate .CER to SAML2 Configuration ITfoxtec.Identity.Saml2

I'm trying to implement SSO using SAML2 and ITfoxtec.Identity.Saml2 package in my ASP.NET MVC ( .NET 6.0 ).
I have the metadata file of the IDP ( Azure AD ) and the .cer certificate file ( both given by the IDP ).
When i'm testing the assertion , i'm getting SAML response success and i can read the claims but when i come to unbind i get " Signature is invalid " , i think because i did not add the public key ( .cer file ) to the Saml config but i'm not sure.
I found how to configure .pfx certificate file ( which required password (private key) ),but not the case for the .cer.
Any ideas please ?
Thanks.
It is enough to read the Azure AD IdP metadata. The IdP metadata contain the public .cer file.
You need to ensure that the code read the certificate correctly in the IdP metadata. Please use the following sample code as a reference.
foreach (var signingCertificate in entityDescriptor.IdPSsoDescriptor.SigningCertificates)
{
if (signingCertificate.IsValidLocalTime())
{
saml2Configuration.SignatureValidationCertificates.Add(signingCertificate);
}
}
if (saml2Configuration.SignatureValidationCertificates.Count <= 0)
{
throw new Exception("The IdP signing certificates has expired.");
}
if (entityDescriptor.IdPSsoDescriptor.WantAuthnRequestsSigned.HasValue)
{
saml2Configuration.SignAuthnRequest = entityDescriptor.IdPSsoDescriptor.WantAuthnRequestsSigned.Value;
}

Not able to connect from Windows Application to IdentityServer4 with SSL

I have a Windows application that is using the "password" grant type. It is able to authenticate to the Identityserver4 without SSL, but not with SSL. The problem is that it is giving an error:
The underlying connection was closed: An unexpected error occurred on a send
I tried it from postman, and it worked, but not from my Windows Application. Below is the code:
var tokenClient = new TokenClient($"{IdentityServer}/connect/token", Constants.ClientId, Constants.ClientSecret);
var tokenResponseTask = tokenClient.RequestResourceOwnerPasswordAsync(username, password, Constants.Scope);
tokenResponseTask.Wait();
return tokenResponseTask.Result;
Below also is another code the I tried, but it doesn't work:
TokenResponse tokenResponse;
string request = $"client_id={clientId}&client_secret={clientSecret}&grant_type={grantType}&scope={scope}&username={username}&password={password}";
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
byte[] result = client.UploadData(endpointUrl, "POST", Encoding.UTF8.GetBytes(request));
string resultJson = Encoding.UTF8.GetString(result, 0, result.Length);
tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(resultJson);
}
Finally, I was able to find the solution under the following link:
Authentication failed because remote party has closed the transport stream
'The underlying connection was closed' error is often seen when the SSL handshake fails.
SSL handshake failure usually has something to do with the relevant SSL certificate and whether or not the certificate is trusted.
Check ...
Whether IdentityServer is configured to run under HTTP and HTTPS.
Your Windows Application is correctly configured for SSL.
Test some of the IdentityServer endpoints using a browser with the https protocol.
Hope this gets you going on a helpful investigation path.

Invalid Signature Key IdentityServer4

I'm facing this exception in my authenticated applications with identityserver4:
SecurityTokenInvalidSignatureException: IDX10503: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.RsaSecurityKey , KeyId:
'. Exceptions caught: ''. token: '{"alg":"RS256","typ":"JWT"}.{"nbf":1501510053,"exp":1501510353,"iss":"http://localhost:5000","aud":"clientId","nonce":"636371068531446271.Nzc2YzRjZGMtN2M0Ny00MGZiLWI3NTQtN2Q2NWIxZGM5MWUyODY2MGE5NTgtYWMzNS00YWJmLWEyMDktNjcwMmJhYTlkYWJk","iat":1501510053,"c_hash":"teGUAAIvU0EY9L1WzjfI2Q","sid":"c870b6184744290472b157ce5992f8e0","sub":"a3915666-8586-476b-9166-b5b183af609e","auth_time":1501508734,"idp":"local","amr":["pwd"]}'.
At this time, I don't have a certificate to use in my Sign in credentials in identity server. So I try this code, sometimes works, but I have sure this is wrong. Someone have a step by step how to use SignInCredentials without a .pfx certificate?
var signinkey = new RsaSecurityKey(RSA.Create());
var signingCredentials = new SigningCredentials(signinkey,
SecurityAlgorithms.RsaSha256);
// Adds IdentityServer
services.AddIdentityServer()
.AddSigningCredential(signingCredentials)
...
Use
services.AddIdentityServer().AddDeveloperSigningCredential()
This will create you a random RSA key pair at first launch and cache it on disk.

Cannot find a token authenticator for the 'Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken' token

I am trying to use WS2007HttpRelayBinding with end to end security mode set to TransportWithMessageCredential. I am using IssuedToken as the credential type. I get the token from a ADFS 2.0 one calling the service I get the following in the on premises wcf trace log
Cannot find a token authenticator for the 'Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken' token type. Tokens of that type cannot be accepted according to current security settings.
update:
This is how I am configuring the service host
ServiceConfiguration serviceConfiguration = new ServiceConfiguration();
serviceConfiguration.ServiceCertificate = GetServiceCertificateWithPrivateKey();
serviceConfiguration.CertificateValidationMode = X509CertificateValidationMode.None;
serviceConfiguration.IssuerNameRegistry = new X509IssuerNameRegistry("localhost");
serviceConfiguration.SaveBootstrapTokens = true;
serviceConfiguration.SecurityTokenHandlers.AddOrReplace(new Saml2SecurityTokenHandler());
serviceConfiguration.SecurityTokenHandlers.Configuration.AudienceRestriction.AllowedAudienceUris.Add(new Uri("https://mynamespace.servicebus.windows.net/Service1/"));
FederatedServiceCredentials.ConfigureServiceHost(host, serviceConfiguration);
host.Open();
Can you verify if Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler is added in
<securityTokenHandlers>
<add type="Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler" />
</securityTokenHandlers>
Edit: And also be sure to verify certificates configuration.
Edit: Maybe this will also help MSDN WCF forums
The binding security elements is set to look for SAML 1.1 tokens. I added the following code to the server after constructing the ‘CustomBinding’ element
IssuedSecurityTokenParameters issuedTokenParameters =
myBinding.Elements.Find<TransportSecurityBindingElement>().EndpointSupportingTokenParameters.Endorsing[0] as IssuedSecurityTokenParameters;
issuedTokenParameters.TokenType = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0";
Alexey's answer is perfect for web.config/app.config modifications. Besides that you can also configure the token handler in code (sample from the How to: Authenticate with a Username and Password to a WCF Service Protected by ACS article (learn.microsoft.com) - How to: Authenticate with a User Name and Password):
//
// This must be called after all WCF settings are set on the service host so the
// Windows Identity Foundation token handlers can pick up the relevant settings.
//
ServiceConfiguration serviceConfiguration = new ServiceConfiguration();
serviceConfiguration.CertificateValidationMode = X509CertificateValidationMode.None;
// Accept ACS signing certificate as Issuer.
serviceConfiguration.IssuerNameRegistry = new X509IssuerNameRegistry( GetAcsSigningCertificate().SubjectName.Name );
// Add the SAML 2.0 token handler.
serviceConfiguration.SecurityTokenHandlers.AddOrReplace( new Saml2SecurityTokenHandler() );

Certificates across servers and WCF

I have a website, wcf service, and a security token service (STS) running on one server. Everything works great. I am now trying to now seperate the peices across servers. When the website trys to login to get the token I get ssl cert errors.
This would be on Server 2008 and IIS 7.5 and my windows 7 IIS 7.5 while i debug.
An error occurred while making the HTTP request to https://x.x.x.x/STS/issue/wstrust/mixed/username. 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...
I generated a self signed cert on the STS server and exported it to the website server. I also exported the key and gave IIS access to the key on the website server. That got past a bunch of WIF errors, it would not run, but I'm not sure that its the right thing to do.
I also have tried [netsh http add sslcert ipport:0.0.0.0:44400 ect...] but im not sure what port to use, ive tried a half dozen different ones and none seem to work, and 443 wont work.
The website is using a WSTrustChannelFactory to create the connection. It bombs on the channel.issue command at the bottom.
var factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress(signInEndpoint));
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = userName;
factory.Credentials.UserName.Password = password;
var channel = factory.CreateChannel();
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointAddress(realm),
KeyType = KeyTypes.Bearer
};
try
{
var genericToken = channel.Issue(rst) as GenericXmlSecurityToken;
** EDIT **
I've also set website servers iis default website https bindings port 443 to use the cert that i imported from the STS server and get the same error.
** End Edit **
I've been all over google and stackoverflow and while many questions seem to be close, none of the approved answers have worked.
Ideas? I'm a server/hardware noob so the "for dummies version" would be nice.
Thanks!
Since u are using a self signed certificate, have u made sure to turn off Certificate Chain Validation or else add it to the trusted store. It looks like u are using the url of IdentityServer, in there u can turn off strong endpoint requirements and on the client use a UserNameWSTrustBinding with only message security.