Custom JwtSecurityTokenHandler not being invoked - model-view-controller

I have a .NET MVC application that uses Azure Active Directory for Auth.
I'm trying to add a custom JWTSecurityTokenHandler to authenticate a console app that performs some basic GET requests against the app. However every request just gets redirected to the Azure AD login page instead of being passed to the JWT handler (my breakpoints and logging statements in the handler are not being hit). Any ideas?
Web.config:
<system.identityModel>
<identityConfiguration>
<audienceUris>
<add value="https://localhost:44300/" />
</audienceUris>
<securityTokenHandlers>
<add type="QS.Admin.Infrastructure.MyJwtHandler, QS.Admin" />
<securityTokenHandlerConfiguration>
<certificateValidation certificateValidationMode="None" />
</securityTokenHandlerConfiguration>
</securityTokenHandlers>
<issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
<authority name="https://[myaccessdomain].accesscontrol.windows.net/">
<keys>
<add thumbprint="[thumbprint]" />
</keys>
<validIssuers>
<add name="https://[myaccessdomain].accesscontrol.windows.net/" />
</validIssuers>
</authority>
</issuerNameRegistry>
<!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
<certificateValidation certificateValidationMode="None" />
</identityConfiguration>
</system.identityModel>
<system.identityModel.services>
<federationConfiguration>
<cookieHandler requireSsl="false" />
<wsFederation passiveRedirectEnabled="true" issuer="https://[myaccessdomain].accesscontrol.windows.net/v2/wsfederation" realm="https://localhost:44300/" requireHttps="false" />
</federationConfiguration>
</system.identityModel.services>

in addition to the above advice,
the jwtsecuritytokenhandlers responsibility is to validate a jwt and serve claims upstream. I don't see session management anywhere in your config, if that is missing, each call to the host will require obtaining a new token from ACS.

The settings in web.config look right.
Couple of things to check :
Make sure ACS is configured to issue JWT tokens for your realm.
If you plug in the JwtSecurityTokenHandler from MS - is it getting hit? This will help in isolating the issue to your custom handler versus settings in ACS or web.config.

Related

How to fix: "Metadata contains a reference that cannot be resolved:'http://<host>:<port><path>?wsdl'." for "Configure WCF Web Service Reference" in vs

I have been trying to publish a WCF web service on my IIS server using a nonstandard HTTPS port. Access to the server should only be possible after authentication (via basic authentication). The web service I created for testing purposes is the base project you get by default when creating a WCF Service Application in Visual Studio. The only modifications I made are in the web.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="SoapApi.Service1">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding"
contract="SoapApi.IService1"/>
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
After the service was published on the local file system and the IIS was configured. I was able to reach the WSDL file on the server after authentication from the browser on my local PC. But if I'm trying to add the service to a simple client application using the Configure WCF Web Service Reference wizard from Visual Studio, I get the following error message:
Metadata contains a reference that cannot be resolved:'http://<host>:<port><path>?wsdl'.
and the full error message:
An error occurred while attempting to find services at 'http://<host>:<port><path>?wsdl'. The remote server returned an error: (403) Forbidden.
Since this error indicates that I don't have access permission, I thought why not turn off authentication and try if it works. I activated anonymous access for the website in IIS and deactivated basic authentication.
Furthermore I changed the following passage in the web.config file:
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
I can still access the WSDL file from my browser, but nevertheless I still get the same error when adding the service reference to the client. The same happens if I test it via dotnet-svcutil http://<host>:<port><path>?wsdl
If I try to add the service reference locally everything works without any issues.
Additional information:
I already installed .NET Framework 4.6 and it's WCF HTTP Activation handler.
I added the permission IIS_IUSRS to the folder containing the service.
Any ideas to why this happens and what I could do to fix this problem?
If you use transport security mode, why not use https addresses? The https/http base address should be configured in IIS site binding module.
In addition, since you are using basic authentication, please turn on anonymous authentication and basic authentication in the IIS authentication module.
On my side, I can add service references correctly using the Core-based console application.
Besides, Please enable the following windows feature for WCF.
Feel free to let me know if there is anything I can help with.

Configure Token-Based Authentication in IIS

I created a WebApi with Token-Based Authentication using this article Token Based Authentication using ASP.NET Web API 2, Owin, and Identity (many thanks to the author of this article) I was successful to create the application and it's working in my local machine.
Problem: When I deploy it in IIS as a subsite (its parent site is using Windows Authentication) it doesn't work. What am I missing. Please help.
References:
My WebApi Config
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" />
<httpModules></httpModules>
<customErrors mode="Off"/>
</system.web>
And my parent Config
<authorization>
<allow users="*" />
<deny users="?" />
</authorization>
It turns out that when I finished my project, I deploy it as a separate application. I cannot deploy it as a subsite. Mixed authentication is a headache so, as much possible, work with your infra/security to sort out what authentication is needed in your application.

Error 404 using asp.net web api

I've got 2 projects: Core and Web.
Core project has API controllers, models, etc. Web project has html pages only.
I'm loading data from API using jQuery. When I do this exactly from Core project (created a view), everything is ok. But when I do this from Web project, I've got error 404, but Fiddler shows everything is ok.
Why is it so? What's a problem?
I found the answer. That is because it's cross domain application. And it's necessary to implement CORS support. It can be done by two ways.
First. Add to section of web.config file next:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Second. Create custom MessageHandler. Like in this post

AngularJS + ASP.NET Web API Cross-Domain Issue

Moving forward with my mobile app development learning process, I've found a new obstacle: Cross-origin Request Sharing or CORS.
I am using a combination of AngularJS + jQuery Mobile (Cordova phone client) and ASP.NET Web API (backend). My issue is that I have not been able to complete a POST request (or any other type of request) to an API controller.
My AngularJS controller uses the $http.post() service method to call the Web API controller. However, Chrome debugger says that the call failed in an OPTIONS request (possibly the CORS preflight request).
I have implemented the CORS action selector from the following post: Enabling CORS in Web API Project. Even tough I can call the api method from Fiddler, AngularJS keeps failing on the OPTIONS preflight request.
Is there anything I should be aware of about AngularJS and cross-domain calls? Any possible solution to my predicament?
Thanks.
You can skip the preflight option request by using content-type : application/x-www-form-urlencoded.
AngularJS:
var user = {
ID: 1,
Name: 'test'
};
$http({
url: "api.localhost/api/users/addUser",
method: "POST",
data: $.param(user),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
withCredentials: true,
}).success(function (data, status, headers, config) {
console.log(data);
})
Web api:
[HttpPost]
public string AddUser(User user)
{
// Do something
return user.Name + " added";
}
Web.config
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://localhost" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept, Cache-Control" />
<add name="Access-Control-Allow-Credentials" value="true" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
</system.webServer>
While stumbling onto this issue with AngularJS 1.3 with Microsoft Web API 2 I found a simple solution to the CORS configuration issue.
First from Nuget intall - Microsoft WebApi Cors
Install-Package Microsoft.AspNet.WebApi.Cors
Then in your WebApiConfig.cs file:
var cors = new System.Web.Http.Cors.EnableCorsAttribute("www.my-angular-web-site.com", "*", "*");
config.EnableCors(cors);
You can also enable CORS everywhere with a * instead of your web site but that defeats the purpose of CORS and opens up security holes - but you can do it for testing.
The WebApi.Cors assembly also lets you enable cors controller by controller or with other more granular details. Other details can be found here on the Web API site.
Check out Thinktecture Cors objects, with those (nugettable) you can get full CORS support in WebApi without any code of your own.
Even with a correct CORS implementation I've had a really strange issue with IIS 7 that was solved by enabling all verbs for WebDav (yes, WebDav - don't ask me why I just followed instructions on a blog post :-D).
Do this:
Open IIS manager, go to your application's Handler Mapping.
Double click the WebDav handler
Click "Request Restriction"
On the "Verbs" tab, select "All verbs".
Again, no idea why WebApi uses WebDav, but this solved problems with POST and DELETE that wouldn't work in spite of a correct CORS implementation.
Mostly the developers while running there UI and service on Localhost face this issue - There are many ways in which this can be resolved - alot of the developers tend to fix it at browser level " but thats a security breach.
Correct method is to fix this at your Web Service Layer- Following video will explain and solve this
Watch CORS- Implementing Cross Origin Resource Sharing ("EXPLAINED - Cross Origin Resource Sharing")!

Cross domain work around with IIS7.5

I am building an application that is ready for release however I have come up against the cross domain scripting problem within my ajax calls.
I am using IIS7.5 and I have the following applications setup
Marketing Application - 'www.mydomain.com' - Used as the marketing website and for registering for a new business.I have a rule that forces any non www. to be www
Business Application - 'https://newbusiness.mydomain.com' - Used to access their services they have subscribed to
API Application - 'https://newbusiness.mydomain.com/api/.......' - Used for business application to do crud operations
API application is an application running under the business application. Containing a number of secured methods and some anonymous ones.
With jquery I am having trouble from my marketing application trying to call the api application. Currently if I want to call the api from my marketing site I am doing something like 'https://api.mydomain.com/api/whatevermethod' because it is cross domain it fails.
Is there anyway that I can somehow map 'https://api.mydomain.com/api/whatevermethod' to be just 'https://mydomain.com/api/whatevermethod' as this would get me around the cross domain problem.
You need to allow cross domain calls in the IIS. You can do this by setting the Access-Control-Allow-Origin and Access-Control-Allow-Headers
ex:
in root web.config
<system.webserver>
<httpprotocol>
<customheaders>
<add name="access-control-allow-origin" value="*" />
<add name="access-control-allow-headers" value="content-type" />
</customheaders>
</httpprotocol>
</system.webserver>
taken from here
Just in case you also got an error 500 from Amila's answer, here's what the whole web.config file content should look like
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="access-control-allow-origin" value="*" />
<add name="access-control-allow-headers" value="content-type" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>

Resources