Tag Archives: Asp.Net

Migrate from ASP.NET Core 1.x to 2.0

I’ve one project made in .net core 1.1 and recently worked on it to move it to .net core 2.0. For this purpose I follow This link.

I’m using HybridAndClientCredentials on the STS server and openid Connect and cookies on the client. Most of the migration is covered by the above link, but I faced issue where most of my claims are missing.

With the ASP.NET Core 1.x, client would have received the claims: nbf, exp, iss, aud, nonce, iat, c_hash, sid, sub, auth_time, idp, amr.

In Core 2.0 we only get sid, sub and idp. What happened?

Microsoft added a new concept to their OpenID Connect handler called ClaimActions. Claim actions allow modifying how claims from an external provider are mapped (or not) to a claim in your ClaimsPrincipal. Looking at the ctor of the OpenIdConnectOptions, you can see that the handler will now skip the following claims by default:

ClaimActions.DeleteClaim("nonce");
ClaimActions.DeleteClaim("aud");
ClaimActions.DeleteClaim("azp");
ClaimActions.DeleteClaim("acr");
ClaimActions.DeleteClaim("amr");
ClaimActions.DeleteClaim("iss");
ClaimActions.DeleteClaim("iat");
ClaimActions.DeleteClaim("nbf");
ClaimActions.DeleteClaim("exp");
ClaimActions.DeleteClaim("at_hash");
ClaimActions.DeleteClaim("c_hash");
ClaimActions.DeleteClaim("auth_time");
ClaimActions.DeleteClaim("ipaddr");
ClaimActions.DeleteClaim("platf");
ClaimActions.DeleteClaim("ver");

If you want to “un-skip” a claim, you need to delete a specific claim action when setting up the handler. The following is the very intuitive syntax to get the amr claim back:

options.ClaimActions.Remove("amr");

Requesting more claims from the OIDC provider

When you are requesting more scopes, e.g. profile or custom scopes that result in more claims, there is another confusing detail to be aware of.

Depending on the response_type in the OIDC protocol, some claims are transferred via the id_token and some via the userinfo endpoint.

So first of all, you need to enable support for the userinfo endpoint in the handler:

options.GetClaimsFromUserInfoEndpoint = true;

In the end you need to add the following class to import all other custom claims

public class MapAllClaimsAction : ClaimAction
    {
        public MapAllClaimsAction() : base(string.Empty, string.Empty)
        {
        }

        public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
        {
            foreach (var claim in identity.Claims)
            {
                // If this claimType is mapped by the JwtSeurityTokenHandler, then this property will be set
                var shortClaimTypeName = claim.Properties.ContainsKey(JwtSecurityTokenHandler.ShortClaimTypeProperty) ?
                    claim.Properties[JwtSecurityTokenHandler.ShortClaimTypeProperty] : string.Empty;

                // checking if claim in the identity (generated from id_token) has the same type as a claim retrieved from userinfo endpoint
                JToken value;
                var isClaimIncluded = userData.TryGetValue(claim.Type, out value) || userData.TryGetValue(shortClaimTypeName, out value);

                // if a same claim exists (matching both type and value) both in id_token identity and userinfo response, remove the json entry from the userinfo response
                if (isClaimIncluded && claim.Value.Equals(value.ToString(), StringComparison.Ordinal))
                {
                    if (!userData.Remove(claim.Type))
                    {
                        userData.Remove(shortClaimTypeName);
                    }
                }
            }

            // adding remaining unique claims from userinfo endpoint to the identity
            foreach (var pair in userData)
            {
                JToken value;
                var claimValue = userData.TryGetValue(pair.Key, out value) ? value.ToString() : null;
                identity.AddClaim(new Claim(pair.Key, claimValue, ClaimValueTypes.String, issuer));
            }
        }
    }

In the end add the last ClaimActions in AddOpenIdConnection options list

options.ClaimActions.Add(new MapAllClaimsAction());
Advertisements

An element with id ‘form1’ could not be found. Script error on page load

When you use Jquery and AJAX on the same form and you included the jQuery file with the <script /> this error will be thrown by VS (specially VS 2010).  To solve this issue just replace the <script /> with <script><script/> tag and it will solve your problem.

Note: This error will only come when you use IE, with every other browser this error will not come, but the thing common on all browsers is that design view is corrupted and the events will not fire as expected or not fire at all

How To Create an ASP.NET HTTP Handler by Using Visual C# .NET

From: microsoft support

Implement the Handler

  1. Open Microsoft Visual Studio .NET. In Visual C# .NET, create a new Class Library project named MyHandler.
  2. Set a reference to the System.Web.dll assembly.
  3. Add the following directive to the class:
    Using System.Web
  4. Rename the class SyncHandler.cs, and then change the class definition to reflect this.
  5. Implement the IHttpHandler interface. Your class definition should appear as follows:
    Public Class SyncHandler: IHttpHandler
  6. Implement the IsReusable property and the ProcessRequest method of theIHttpHandler interface. Because this is a synchronous handler, return False for theIsReusable property so that the handler is not pooled.
    public bool IsReusable
    {
    get {return true;}
    }

    public void ProcessRequest(HttpContext context)
    {
    context.Response.Write(“Hello from custom handler”);
    }

  7. Compile the Project

Deploy the Handler

  1. Create a new directory named Handler under the C:\Inetpub\Wwwroot directory.
  2. Create a subdirectory named Bin in the newly created Handler directory. The resultant path is C:\Inetpub\Wwwroot\Handler\Bin.
  3. Copy MyHandler.dll from your project’s Bin\Debug directory to the C:\Inetpub\Wwwroot\Handler\Bin directory.
  4. Follow these steps to mark the new Handler directory as a Web application:
    1. Open Internet Services Manager.
    2. Right-click the Handler directory, and then click Properties.
    3. On the Directory tab, click Create.
  5. Follow these steps to create an application mapping for the handler. For this handler, create a mapping to the Aspnet_isapi.dll file for the *.sync extension. Whenever a .sync file is requested, the request is routed to ASP.NET, and ASP.NET executes the code in the handler.
    1. Right-click on the Handler Web application, and then click Properties.
    2. On the Directory tab, click Configuration.
    3. Click Add to add a new mapping.
    4. In the Executable text box, type the following path: Microsoft Windows 2000:
      C:\WINNT\Microsoft.NET\Framework\<version#>\Aspnet_isapi.dll

      Microsoft Windows XP:

      C:\WINDOWS\Microsoft.NET\Framework\<version#>\Aspnet_isapi.dll
    5. In the Extension text box, type .sync.
    6. Make sure that the Check that file exists check box is cleared, and then clickOK to close the
      Add/Edit Application Extension Mapping dialog box.
    7. Click OK to close the Application Configuration and the Handler Propertiesdialog boxes.
  6. Close Internet Services Manager.

Configure the System

  1. In the C:\Inetpub\Wwwroot\Handler directory, create a new file named Web.config.
  2. Add the following code to Web.config: <configuration> <system.web> <httpHandlers> <add verb="*" path="*.sync" type="MyHandler.SyncHandler, MyHandler" /> </httpHandlers> </system.web> </configuration> In the verb="*" attribute, we instruct the handler to process a request that uses any verb (for example, POST, HEAD, GET, and so on). If you want this handler to process only the POST request, change this to verb="POST". In the path="*.sync" attribute, we instruct the handler to process any incoming requests for files with the .sync extension. In the type="MyHandler.SyncHandler, MyHandler" attribute, we instruct the handler that processes the request to implement in the MyHandler.SyncHandlernamespace, and this class resides in the MyHandler assembly.