desktop client application for SSO using SAML - web-services

I need to write a desktop based client application which does some web service method calls to a SharePoint server, after doing a SAML based SSO authentication.
I found that SAML SSO is mostly used from the browser which takes care of all the details. According to this question, it seems there is a technology in SAML 2.0 called ECP just for enabling non browser based clients.
Yet some applications like SharePoint 2010/2013 only support SAML 1.1; what can be used in this case?

You haven't mentioned technology - i can share my experience.
We're required to have a SSO in the desktop application (WPF) that is using the WCF services. I have started with infomation from this link. The solution is to use WIF for retrieving the SAML token from identity provider and using it to establish the connection to our backend server.
To obtain the token
WSTrustChannelFactory GetTrustFactory()
{
var binding = new WS2007HttpBinding(TrustChannelBindingConfiguration);
return new WSTrustChannelFactory(binding, StServiceUri);
}
SecurityToken GetTokenFromSts()
{
using (var trustFactory = GetTrustFactory())
{
// here is the code to set trustFactory.Credentials
trustFactory.TrustVersion = TrustVersion.WSTrust13;
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointReference(YourServiceUri),
KeyType = KeyTypes.Bearer
};
var channel = (WSTrustChannel) trustFactory.CreateChannel();
try
{
return channel.Issue(rst);
}
catch (MessageSecurityException msex)
{
channel.Abort();
throw new EMException(msex.InnerException.Message, msex);
}
}
}
Then the obtained token is used in service calls:
securityToken = GetToken();
// 2. Create a channel with issued token to YourServiceInterface
// create binding and turn off sessions
var binding = new WS2007FederationHttpBinding(FederationBinding);
try
{
var factory = new ChannelFactory<YourServiceInterface>(binding,
new EndpointAddress(YourServiceUri));
factory.Credentials.SupportInteractive = false;
var channel = factory.CreateChannelWithIssuedToken(securityToken);
// 3. Call YourMethod() on secured channel
return channel.YourMethod();
}
catch {...}
The main approach from the link hasn't been really changed - we just added token caching and incorporated this code in our channel handling framework.
The code is used to authenticate desktop client against ADFS server and use claims in our backend server for authorizations.

Related

Can I define static claims to be returned to a Service Provider?

I have a use-case where a SAML2 application expects certain attributes in the SAML2 assertion. These are not present in user attributes, but they should have static values which are returned in every SAML2 assertion for that service provider.
Is there any way to define such static attributes/claims in WSO2 IS admin console? I know I could create a custom claims handler with Java, but I'm looking first for solutions not requiring custom code.
This issue was similar, but the answer didn't apply to the general case: wso2is any way to code claim to return static text
You can use an Adaptive Authentication script for this. (Simple scripting supported via Management Console)
Example :
function onLoginRequest(context) {
executeStep(1, {
onSuccess: function (context) {
var user = context.currentKnownSubject;
var countryClaim = 'http://wso2.org/claims/country';
var countryValue = user.localClaims[countryClaim];
if (countryValue == null){
Log.info('Updating the address - country claim for user.');
context.steps[1].subject.localClaims[countryClaim] = 'Canada';
}
Log.info('Testing of adding default claim value to user.');
}
});
}
Documentation
Adaptive Authentication
Adaptive Authentication JS API Reference

Get Azure AD Access token from .Net Standard 2.0 unit test

I am having a .Net Core 2.0 asp.net mvc web application. For the same I have a .Net Standard 2.0 unit test project. For the unit test written I have to call a Azure AD protected Web API. Can anyone let me know how can we get azure ad access token from a unit test project in .net standard 2.0.
It is possible in .Net framework as it has "UserPasswordCredential" class available in the "Microsoft.IdentityModel.Clients.ActiveDirectory" dll. But this class is removed in .Net Standard 2.0 (https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/issues/482)
I've used something like this for integration tests:
string tokenUrl = _authority + "oauth2/token";
var req = new HttpRequestMessage(HttpMethod.Post, tokenUrl)
{
Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "password",
["client_id"] = settings.ClientId,
["client_secret"] = settings.ClientSecret,
["resource"] = _resourceUri,
["username"] = settings.UserName,
["password"] = settings.Password
})
};
HttpResponseMessage res = await _client.SendAsync(req);
string json = await res.Content.ReadAsStringAsync();
AadTokenResponse tokenResponse = JsonConvert.DeserializeObject<AadTokenResponse>(json);
There's a few class-level fields like the AAD authority, API resource URI and an HttpClient.
So what this does is acquire an access token using the Resource Owner Password Credentials Grant flow.
This is one of those few cases where using this flow actually makes sense.
We acquire an access token in a user's context without a login window.
This flow should not be used when something better is available, and in this case also requires that the user is not federated, does not have MFA etc.
You'll probably want to cache the token so you don't hammer the token endpoint from your tests pointlessly.

SOAP Exception when trying to Access GP WebServices

I am trying to write a program that simply connects up to a GP WebService and invokes it's GetCustomerList() method to get customers from Great Plains. The code I am outlining below is an duplication of what I was able to find in the documentation, however, when I run it I am getting a SoapException. I am not sure if I am missing credentials (eg. username and password) or if I am even invoking this properly. I believe that I have the Security settings set correctly in the Dynamics Security Console, but I am not 100% sure or if there is anything else I need to configure. Any help would be greatly appreciated.
public IList<string> GetCustomerNames()
{
//Added a ServiceReference to the actual WebService which appears to be working
var service = new DynamicsGPClient();
var context = new Context();
var customerKey = new CustomerKey();
var companyKey = new CompanyKey();
//Trying to load the test data
companyKey.Id = (-1);
context.OrganizationKey = (OrganizationKey)companyKey;
//Trying to load the test data
customerKey.Id = "AARONFIT0001";
var customers = service.GetCustomerList(new CustomerCriteria(), context);
return customers.Select(x => x.Name).ToList();
}
Sounds like a security issue ... are you getting a specific error message ... that might be helpful ...
Also found this ...
It sounds to me like you need a Windows App Pool Identity on your
webservice. Right now you have the IIS Security set to "anonymous", so the
clients aren't required to pass the credentials when they call your methods.
You'll need to turn that off and run your app pool as a windows account. Once
you've got that working, you can choose if you want to just add that one App
Pool identity into the security for webservices, and have all the operations
done as that account (poor security), or, in your wrapper, you could use the
HTTP User's context identity, and set it to the "WorkOnBehalfOf" property for
the GP WebService call you're actually using.
You'll have to give the App
Pool identity "WorkOnBehalfOf" permission in the web service security
console, and then whichever users you want to call the webservice. This keeps
the security model intact, and you're authorizing that the users calling the
wrapped webservice actually do have permission to call the original GP
Webservice methods. (This is how Business Portal forwards requests to the
webservices.)
https://groups.google.com/forum/?fromgroups=#!topic/microsoft.public.greatplains/W7gAo_zXit8

Custom Basic Authentication of a Web service

I'm having a small issue with implementing custom basic authentication for a asmx in .net 4.0.
I've created the HttpModule which would start the authentication process of the web service consumer runnig this code,
HttpApplication application = (source as HttpApplication);
HttpContext context = application.Context;
if ( VirtualPathUtility.GetFileName(context.Request.FilePath).Contains("svcEWS.asmx"))
{
string username = "", password = "";
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Basic"))
{
//Authenticate here
}
}
However there is no authentication header present whenever this code is reached.
The consuming web app is simply calling,
EWS.svcEWS svcEWS = new EWS.svcEWS();
svcEWS.Credentials = new NetworkCredential("admin", "admin", "example.com");
svcEWS.HelloWorld();
IIS is set to run with anonymous authentication to anonymous authentication to prevent it from catching any auth requests.
Is there something I'm missing to have the client pass the correct header to my module?
I was forgetting to reject the first request with 401 code to force authentication. Doing so fixes the problem, as the invoker re sends the request with the auth header.

Authorize proxy access in code if customer is using Microsoft ISA Server

my code is providing an access to our web service.
WebProxy proxy = new WebProxy(ProxyURL, ProxyPort);
proxy.UseDefaultCredentials = false;
NetworkCredential nc = new NetworkCredential( ProxyLogin, ProxyPassword);
proxy.Credentials = nc;
myWebService.Proxy = proxy;
My problem is that customer doesn't know ProxyLogin and ProxyPassword, especially if he is running Microsoft ISA server. Company policy doesn't allow him to know password and login.
Is there anyway to reach authorization information by code?
There is no way to get password by code. If there was a way it would be a security vulnerability.
The user should have proxy access for his account. If he don't have, Than this is the end of it. If he has proxy access than your application should use his credentials.
proxy.UseDefaultCredentials = true;