Call a WCF service protected by ACS, which uses ADFS as IDP - wcf

Following this post I have created a WCF client which:
Uses ADFS to authenticate users against AD.
Provides a SAML2 ticket to the caller.
Uses the supplied SAML2 ticket to call the WCF Service.
This is working great, however the next part of my problem is to extend this to use Azure ACS.
I added the RP to ACS, and changed the STS reference to point to ACS using Add STS Reference in Visual studio.
I have extended the Token.GetToken method, supplying the token into the following method:
public static SecurityToken GetToken(SecurityToken adfsToken, string appliesTo, string idpEndpointAddress, out RequestSecurityTokenResponse rsts)
{
WS2007HttpBinding binding = new WS2007HttpBinding();
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(binding, new EndpointAddress(idpEndpointAddress));
trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
trustChannelFactory.ConfigureChannelFactory();
// Create issuance issuance and get security token
RequestSecurityToken requestToken = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue);
requestToken.AppliesTo = new EndpointAddress(appliesTo);
WSTrustChannel tokenClient = (WSTrustChannel)trustChannelFactory.CreateChannelWithIssuedToken(adfsToken);
SecurityToken token = tokenClient.Issue(requestToken, out rsts);
return token;
}
To the following endpoint:
https://test.accesscontrol.windows.net/v2/wstrust/13/issuedtoken-symmetric
But I get the following exception:
Secure channel cannot be opened because security negotiation with the
remote endpoint has failed. This may be due to absent or incorrectly
specified EndpointIdentity in the EndpointAddress used to create the
channel. Please verify the EndpointIdentity specified or implied by
the EndpointAddress correctly identifies the remote endpoint.
With an inner exception of:
ACS10001: An error occurred while processing the SOAP header.
What do I need to configure in ACS to get this working with the token supplied by ADFS?
Do I need to use the token supplied by ACS, or can I use the one supplied by ADFS in the service? (It appears to be working..)

Take a look at the linked ACS sample, which seems to be doing exactly what you're asking.

Related

Execute RestAPI Azure DevOps Services - Authentication with username & Password no PAT

Can i Use User/Password combination to run RestAPI to Azure DevOps Services?
Short answer NO. - see explanation at marked answer
I tried to find a way to get RestAPI working without PAT or Create a Token from Current Login Info and failed
The following Code Return 401:
using System.Net;
byte[] bytes = System.Text.Encoding.ASCII.GetBytes("user:password");
string patEncoded = Convert.ToBase64String(bytes);
var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://dev.azure.com/<ORG>/_apis/wit/workitems/22289?api-version=6.0");
httpWebRequest.Headers.Add("Authorization", "Basic " + patEncoded);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
Any Advice is much appreciated
I do not want to create an app and register it on the tenant .
Authenticate your web app users for REST API access, so your app doesn't continue to ask for usernames and passwords. Azure DevOps Services uses the OAuth 2.0 protocol to authorize your app for a user and generate an access token. Use this token when you call the REST APIs from your application.
For the Authentication mechanism, REST API is using the mention-aboved authentication mechanism to be authentication.
userName & password: Azure DevOps no longer supports Alternate Credentials authentication since the beginning of March 2, 2020. Here is the document.

Authenticate an EWS WCF service by using OAuth and refresh access token

I am trying to call Exchange web services (EWS) end points from my WCF service using OAuth authentication.
I have registered the app on Azure portal and able to generate and authenticate it using access token.
My question is about how I can refresh the token in WCF service. It seems access token has an hour validity.
// Using Microsoft.Identity.Client 4.22.0
var cca = ConfidentialClientApplicationBuilder
.Create(ConfigurationManager.AppSettings["appId"])
.WithClientSecret(ConfigurationManager.AppSettings["clientSecret"])
.WithTenantId(ConfigurationManager.AppSettings["tenantId"])
.Build();
// The permission scope required for EWS access
var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
//Make the token request
var authResult = await cca.AcquireTokenForClient(ewsScopes).ExecuteAsync();
Followed below link for this.
https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
Thanks
In your WCF client you want to do something like How to add a custom HTTP header to every WCF call? so you have a piece of code that runs before any request is made that calls AcquireTokenForClient which should use the Token Application Cache (so it will either give you the current token if valid or acquire a new token if expired).

Get user info and other claims in Azure Function with Identity server

I am having an application where Authentication is done using IdentityServer4 with Azure AD as an OpenID provider. IdentityServer4 is hosted in Azure App service. After successful authentication, I am able to get access token in Angular application. Access token is passed to .Net Core based RESTful API which is hosted in Azure Function 3.x.
In my Azure function I would like to get user info and other claims without hitting the end point "/connect/userinfo" of IdentityServer4.
Something similar to following for getting Claims would be helpful
[FunctionName("MyFunctionName")]
public static HttpResponseMessage Run(
[HttpTrigger(
AuthorizationLevel.Anonymous,
"get", "post",
Route = "MyFunctionName")]HttpRequestMessage req,
ILogger log,
ClaimsPrincipal claimsPrincipal)
{
// My function code here...
}
How do I get I user info and other claims in Azure function where Authentication is done by IdentityServer4 with Azure AD as OpenID provider
If you have a valid access token, then you can make a request on your own to the UserInfo endpoint to retrieve the remaining user details.
Read more about it here
The only option if you don't want to access the userinfo endpoint is to include the required data in the tokens directly. Here you need to do a trade-of between token size vs convenience. Then you get a really stateless system.
If you don't want to hit user info end point of Identity Server to get the user info and other claims, here is what needs to be done.
Add the claim info to the authorization token
Parse the authorization token and extract the user info and other claim information.
The downside of this approach is that the token size is increased but advantage is that you don't need hit userinfo end point which saves your http request(s). So there are trade offs between each approach.
Here is how you can add claims info while configuring your api in Identity Server. Typically this information resides in Config.cs if you have used Identity Server template
public static IEnumerable<ApiResource> GetApis()
{
var apiResourceList = new List<ApiResource>
{
new ApiResource(IdentityServerConstants.LocalApi.ScopeName)
{
UserClaims =
{
JwtClaimTypes.Email,
JwtClaimTypes.PhoneNumber,
JwtClaimTypes.GivenName,
JwtClaimTypes.FamilyName,
JwtClaimTypes.PreferredUserName
},
}
};
return apiResourceList;
}
For parsing and validating the token please follow the blog Manual token validation in Azure Function
This StackOverflow thread is also very useful.

Network calls /.well-known/openid-configuration/ and /.well-known/openid-configuration/jwks

I have :
Identity server 4,
Mvc app with OpenId Connect and Hybrid flow
WebApi app
Assume user already got cookies with id_token and access token.
Then he calls an action from mvc app:
var client = new HttpClient();
client.SetBearerToken(accessToken);
// call webapi from mvc
var content = await client.GetStringAsync("http://localhost:5001/api/resource-with-policy");
In fiddler i see two calls:
GET /.well-known/openid-configuration/
GET /.well-known/openid-configuration/jwks
As i assume WebApi sees [Authorize] attribute on action and make these calls.
What's purpose of these calls?
WebApi is configured this way:
.AddJwtBearer("Bearer", options =>
{options.Authority = "<is4-url>";
options.RequireHttpsMetadata = false;
options.Audience = "Api1";
});```
The JWT token which is signed by Security Token Service in private key. A JWT token is a non-encrypted digitally signed JSON payload which contains different attributes (claims) to identify the user. The signature is the last part of the JWT and needs to be used for verification of the payload. This signature was generated with the algorithm described in the header(RS256 for example) to prevent unauthorized access.Please refer to this document for more details about JWT token .
To validate signature , firstly we should retrieve and cache the singing tokens (public key) :1)The first call is to the discovery endpoint. It's URL is formed as /.well-known/openid-configuration .2) Then you will find lots of metadata here including the jwks_uri endpoint address which will send get request to get the keys to validate the token's signature .
Token signing is implemented according to JSON Web Key spec. Using Key ID and X.509 certificate thumbprint values from the token's header (kid and x5t parameters respectively) and then find the appropriate public key in the obtained collection of keys to verify the signature with n(Modulus) and e(Exponent). Here is one code sample .
Those are part of the OpenID Connect protocol.
Your API uses the first request to discover parameters it uses for token validation.
That configuration document contains e.g. the valid issuer value to expect in tokens.
The second request is getting the public signing keys for tokens.
That URL is in the first document.
So it's all data used by the API to validate tokens, so you don't need to manually configure them.

How to retrieve token from acs using client certificate?

I want to use ACS as a STS for the service bus. I've managed to use ACS for authentication for a web service. However, the service bus requires a token and I don't know how to retrieve such from the ACS?
In short, I want my client wcf services to be able to use the service bus by authenticating with certificates that matches certificates stored as service identities in the acs (the one corresponding to the service bus -sb).
Also, I'm using NetTcpRelayBinding for the Service Bus.
I guess I can use a token from acs if I can just retrieve it using the client certificate...?
Getting a token from ACS using client certificate credentials over WCF is a well supported scenario.
There is an ACS sample that does WCF client certificate auth available here, look for Acs2CertificateBindingSample. Points of interest are how to create the binding that obtains a token from ACS:
public static Binding CreateServiceBinding(string acsCertificateEndpoint)
{
return new IssuedTokenWSTrustBinding(CreateAcsCertificateBinding(), new EndpointAddress(acsCertificateEndpoint));
}
public static Binding CreateAcsCertificateBinding()
{
return new CertificateWSTrustBinding(SecurityMode.TransportWithMessageCredential);
}
And how to create the channel factory using this binding, and how to specify your client certificate credential:
ChannelFactory<IStringService> stringServiceFactory = new ChannelFactory<IStringService>(Bindings.CreateServiceBinding(acsCertificateEndpoint), serviceEndpointAddress);
// Set the service credentials and disable certificate validation to work with sample certificates
stringServiceFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
stringServiceFactory.Credentials.ServiceCertificate.DefaultCertificate = GetServiceCertificate();
// Set the client credentials.
stringServiceFactory.Credentials.ClientCertificate.Certificate = GetClientCertificateWithPrivateKey();
The sample is not using service bus, just a simple "IStringService" interface, but if you incorporateyour NetTcpRelayBinding into the binding composition, the same mechanisms should be applicable to your scenario.