How to call WCF service with ADFS issued Security Token - web-services

I have an MVC web applicationt that has been confuigured to connect to ADFS to authenticate users and get a security token. The application then needs to call a WCF service using that security token.
The config of the web app is
<system.identityModel>
<identityConfiguration saveBootstrapContext="true">
<claimsAuthenticationManager type="MvcApplication1.Security.ClaimsTransformer, MvcApplication1" />
<claimsAuthorizationManager type="MvcApplication1.Security.AuthorisationManager, MvcApplication1" />
<audienceUris>
<add value="https://edd05rgard.hd.dev/adfsproto/web/" />
</audienceUris>
<issuerNameRegistry type="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<trustedIssuers>
<add thumbprint="49F27C0DD1044D73011894450727E3C3E55DA428" name="http://EDV05TESTADFS1.hdtest.hd.dev/adfs/services/trust" />
</trustedIssuers>
</issuerNameRegistry>
</identityConfiguration>
<federationConfiguration>
<cookieHandler requireSsl="true" />
<wsFederation passiveRedirectEnabled="true"
issuer="https://edv05testadfs1.hdtest.hd.dev/adfs/ls/"
realm="https://edd05rgard.hd.dev/adfsproto/web/"
reply="https://edd05rgard.hd.dev/adfsproto/web/"
requireHttps="true" />
</federationConfiguration>
This successfully gets the token from ADFS and I can transform claims within the app as expected.
I then try to make a call to a WCF service using the supplied security token:
BootstrapContext bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext;
var binding = new WS2007FederationHttpBinding(WSFederationHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Message.IssuedKeyType = SecurityKeyType.BearerKey;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.IssuerAddress = new EndpointAddress("https://edv05testadfs1.hdtest.hd.dev/adfs/ls");
var endpoint = new EndpointAddress("https://edd05rgard.hd.dev/adfsproto/service/ClaimsService.svc");
var factory = new ChannelFactory<IClaimsService>(binding, endpoint);
factory.Credentials.SupportInteractive = false;
factory.Credentials.UseIdentityConfiguration = true;
var context = (BootstrapContext)((ClaimsIdentity)Thread.CurrentPrincipal.Identity).BootstrapContext;
var channel = factory.CreateChannelWithIssuedToken(context.SecurityToken, endpoint);
var result = channel.GetClaimsWithDelegation();
When this code is executed the last line causes an exception:
An error occurred when processing the security tokens in the message.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ServiceModel.FaultException: An error occurred when processing the security tokens in the message.
Am I calling the service in the correct way? How can I investigate the errors in the security token?

Related

Azure WebJobs and Service Bus : 2 settings for the same thing?

When I add the following NuGet package to my WebJob: Microsoft.Azure.WebJobs.ServiceBus 2.0.0,
two new items are added to the app.config file.
It seems they are both used to define the Service Bus connection string.
Can I get rid of one of them?
<connectionStrings>
<add name="AzureWebJobsServiceBus" connectionString="..." />
</connectionStrings>
<appSettings>
<!-- Service Bus specific app setings for messaging connections -->
<add key="Microsoft.ServiceBus.ConnectionString" value="..." />
</appSettings>
Thanks for your help!
It seems they are both used to define the Service Bus connection string. Can I get rid of one of them?
According the source code of ServiceBusConfiguration, WebJob Service Bus SDK(ServiceBusTrigger) will use the connection string which stored under the connectionStrings section.
public string ConnectionString
{
get
{
if (!_connectionStringSet)
{
_connectionString = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.ServiceBus);
_connectionStringSet = true;
}
return _connectionString;
}
set
{
_connectionString = value;
_connectionStringSet = true;
}
}
You can also set the connection string at runtime.
JobHostConfiguration config = new JobHostConfiguration();
config.UseServiceBus(new ServiceBusConfiguration() { ConnectionString = "" });
JobHost host = new JobHost(config);
If you want to create a instance of Service Bus Client(for example QueueClient) to do some specific operations, you could use the Service Bus connection string configured in appSettings.
//Use CloudConfigurationManager to read the connection string stored in appSettings
string connectionString = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString");
var client = QueueClient.CreateFromConnectionString(connectionString, "queueName");

MVC 5 + ASP Identity authorization - sharing cookie in subdomains

I have local website with subdomains like:
localhost:55307
aaa.localhost:55307
bbb.localhost:55307
It works perfectly except authorization - if I log in in localhost:55307 I'm not logged in aaa.localhost:55307 because my subdomains are treated as separate domain. I looking for solution but I can't find any for Asp Identity (Form authentication in MVC 4 it's useless).
Based on some questions and answers in SO I did:
Edit CookieAuthenticationOptions class in Startup.Auth.cs as below:
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
CookieDomain = ".localhost",
ExpireTimeSpan = new TimeSpan(0,12,0,0,0),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
Get MachineKey from IIS Manager and add to web.config:
<system.web>
<authentication mode="None" />
<machineKey validationKey="61D42DE996486DEA64CEA26C0373C547E0D07108789662C2D2E15210A65C475925055009D962FEB3D5D93E9BEA3E3717187F1BCBF63E386EB198F641E6157044" decryptionKey="06CF7C1C31BDBD4E7056D0F3531BE253E98A658B50974155" validation="SHA1" decryption="Auto"/>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" maxRequestLength="1073741824" />
</system.web>
Now i can login but cookies aren't shared - I still logged in one subdomain.
PS. I now that there is a lot of similar questions in StackOberflow but no one of them is about MVC 5 and ASP Identity and no of them got solutions.

Error when accessing ESB Proxy with Jaggery WSStub

I created a web service and was able to send requests to it from a serverside Jaggery.js script with no problem. Then I created a WSDL Proxy Service inside WSO2 ESB and tested it using the "Try it!" feature.
After I redirected my serverside script from the original web service to its proxy inside ESB, I got the error in System Logs:
The endpoint reference (EPR) for the Operation not found is /services/BpmAdderProcessProxy.BpmAdderProcessProxyHttpSoap11Endpoint and the WSA Action = urn:anonOutInOpResponse. If this EPR was previously reachable, please contact the server administrator.
To see in detail what was happening I activated the "SOAP Message Tracer" of the ESB. Suddenly my serverside script could access the webservice via my ESB proxy. Then I deactivated the "SOAP Message Tracer" and the error message was back again. Is my serverside script correct? Or does the debugging tool modify behavior of debugged code?
I'm a JavaScript developer. Actually Jaggery and UES are targeted at people like me. I'm not supposed to look inside Java code, am I? Is there a forum where JavaScript developers discuss WSO2 UES and Jaggery?
My serverside code is as follows:
<%
var x = request.getParameter("x");
var y = request.getParameter("y");
//var sum = parseInt(x) + parseInt(y);
var sum = add(parseInt(x), parseInt(y));
response.content = {
success: true,
data: {
result: sum
}
};
function add(x, y) {
var ws = require('ws');
var stub = new ws.WSStub("http://02-128:8280/services/BpmAdderProcessProxy?wsdl");
var process = stub.services["BpmAdderProcessProxy"].operations["process"];
var payloadTemplate = process.payloadXML();
var payload = replaceQuestionMarks(payloadTemplate, arguments);
var resultXml = process.request(payload);
var resultValue = resultXml.children().text();
return parseInt(resultValue);
}
function replaceQuestionMarks(template, values) {
var i = 0;
return template.replace(
/\?/g,
function() {
return values[i++];
}
);
}
%>
In ESB v4.8.1, pass-through transport is enabled by default and it does not support SOAP body based dispatching (it does not build the message so it can't acces the body's first element to find the operation)
You can append the operation name to the endpoint url : http://host:8280/services/BpmAdderProcessProxy/OperationName
You can add this parameter in your proxy conf (BpmAdderProcessProxy) in WSO2 ESB : <parameter name="disableOperationValidation" locked="false">true</parameter>
You can edit wso2esb/repository/conf/axis2/axis2.xml and replace <handler class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher" name="SOAPMessageBodyBasedDispatcher"/>
with
<handler class="org.apache.synapse.core.axis2.SynapseSOAPMessageBodyBasedDispatcher" name="SOAPMessageBodyBasedDispatcher"/>

Integrated Windows Security when calling an ASMX service

I have some issues with an ASMX web service running on Win XP with IIS 5.1. The IIS is set up with Integrated Windows Authentication and with anonymous access disabled. (When I have anonymous access enabled, everything works as a charm.)
However, when I turn of anonymous access and run with only Integrated Windows Authentication on my IIS, I get the following exception:
The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'.
This exception is generated from my really simple console application that I'm using just to test the concept:
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows; // .None;
binding.UseDefaultWebProxy = false;
EndpointIdentity spn = EndpointIdentity.CreateSpnIdentity("WORKGROUP/VirtualXP-91051");
Uri uri = new Uri("http://169.254.91.91/MyWebSite/MyService.asmx");
EndpointAddress address = new EndpointAddress(uri, spn);
MyServiceSoapClient client = new MyServiceSoapClient(binding, address);
client.ClientCredentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
String req = "( the request string is blanked out.. ;) )";
string resp = client.ReqAddressData(req);
Console.WriteLine(resp);
Console.ReadLine();
The interesting part of App.config:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
This isn't rocket science, so I must be missing something obvious. I've done some searching here on SO, and eve though I can find many similar questions I've found nothing that solved my problem.

Trouble with SOAP request from Flex

SUM: I ended up having to form the XML manually. I also had to create an Operation and use its send(); method rather than just doing something like WebService.MyServiceFunction(); - not sure why that was the case.
I send off the request as follows:
var xm:XML =
<SetPropertiesForCurrentUser xmlns="http://asp.net/ApplicationServices/v200">
<values xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d4p1:KeyValueOfstringanyType>
<d4p1:Key>{obj.Key}</d4p1:Key>
<d4p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:string">{obj.Value}</d4p1:Value>
</d4p1:KeyValueOfstringanyType>
</values>
</SetPropertiesForCurrentUser>;
var profileService:WebService = new WebService();
profileService.useProxy = false;
profileService.loadWSDL(url);
var o:Operation = profileService.SetPropertiesForCurrentUser;
o.send(xm);
Here’s my scenario:
I have ASP.NET web services to handle authentication, user roles, and user profiles (default ASP.NET AuthenticationService, RoleService, and ProfileService, to be exact).
So from my Flex web app, I am able to successfully call the ASP.NET service. For example, something like this works fine:
var profileService:WebService = new WebService();
profileService.useProxy = false;
profileService.GetAllPropertiesForCurrentUser.addEventListener("result",getAllPropertiesForCurrentUser_EventHandler);
profileService.addEventListener("fault",getAllPropertiesForCurrentUserFault_EventHandler);
profileService.loadWSDL(url);
profileService.GetAllPropertiesForCurrentUser();
I run into trouble when I need to pass a Dictionary object to another function on the service (SetPropertiesForCurrentUser). The .NET service asks for this type of value:
System.Collections.Generic.IDictionary(Of String, Object)
Here are the two pertinent entries from the web.config entry from my ASP.NET service:
<properties>
<clear/>
<add name="coordinateFormat" />
</properties>
...
<profileService enabled="true"
readAccessProperties="coordinateFormat"
writeAccessProperties="coordinateFormat"/>
So after putting together a SOAP request from a Silverlight app (which works as expected) I’ve narrowed it down to a difference in the XML request sent to the SOAP handler:
From Flex:
<tns:Value>DMS</tns:Value>
From Silverlight:
<d4p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:string">DMS</d4p1:Value>
If I take the request generated by Flex, catch it with Fiddler, modify that one line to include the “type” namespace – it works.
Anyone have an idea how I can get that namespace onto my variable that is passed to the SOAP handler from Actionscript? Here is my code for sending off that SetPropertiesForCurrentUser function:
var obj:Object = {};
obj["Key"] = "coordinateFormat";
obj["Value"] = DMS;
var profileService:WebService = new WebService();
profileService.useProxy = false;
profileService.SetPropertiesForCurrentUser.addEventListener("result",setPropertiesForCurrentUser_EventHandler);
profileService.addEventListener("fault",setPropertiesForCurrentUserFault_EventHandler);
profileService.loadWSDL(url);
profileService.SetPropertiesForCurrentUser(new ArrayCollection([obj]),false);
Thanks,
Josh
The default SOAPEncoder that is used is some what limited in its capabilities (like not including the type attribute you mentioned above). Luckily, there is a way to control that by writing your own encoder.
see this link at adobe (read part about using custom web service serialization) Link on Adobe's Site