Jim Rogers

Lives in Baton Rouge, LA, with two dogs, one cat, and one lovely wife. I'm a lead developer for GCR Incorporated.

Katrin and Jim

Month List

ACS in Azure staging

by Jim Feb 14, 2011 9:59 AM

During my research into Access Control Services (ACS) I ran into a couple of instances of people wondering about how to deploy an ACS authentication solution to Azure staging. The tricky part is that the ‘audience URI’ list is in the web.config file, which can’t modified after deployment – and this list should include the URL of the site, which is generated during deployment for Azure staging. Catch 22.

I figured there should be a way to modify the configuration setting programmatically, and after some fiddling I’ve found one.

The first step is to hang onto the configuration object at the time that it’s created, by putting it in the application state

void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
{
    // hang onto this object for later; we'll need to add ourselves to the audience uri list
    Application["ServiceConfiguration"] = e.ServiceConfiguration;

it’s probably possible, but not convenient, to construct the correct URL at this point, in a generic way. In Azure, there are meaningless port numbers attached to the actual HttpRequest.Url, so we’re going to build the URL using this special method:

protected string GetApplicationUri()
{
    //
    // In the Windows Azure environment, build a wreply parameter for the SignIn request
    // that reflects the real address of the application.
    //
    HttpRequest request = HttpContext.Current.Request;
    Uri requestUrl = request.Url;
    var wreply = new StringBuilder();

    wreply.Append(requestUrl.Scheme);     // e.g. "http" or "https"
    wreply.Append("://");
    wreply.Append(request.Headers["Host"] ?? requestUrl.Authority);
    wreply.Append(request.ApplicationPath);

    if (!request.ApplicationPath.EndsWith("/"))
        wreply.Append("/");
    return wreply.ToString();
}

The place to inject the dynamically generated Uri is during the redirect to ACS; at this point we’ve got the right information in the host header to reliably construct our URL.

void WSFederationAuthenticationModule_RedirectingToIdentityProvider(
    object sender, 
    RedirectingToIdentityProviderEventArgs e)
{
    var wreply = GetApplicationUri();

    e.SignInRequestMessage.Reply = wreply;
    e.SignInRequestMessage.Realm = wreply;

    // Our our uri to the list of those we'll accept in the incoming token
    var myUri = new Uri(wreply);
    var allowedUris = ((ServiceConfiguration)Application["ServiceConfiguration"])
        .AudienceRestriction.AllowedAudienceUris;

    if (!allowedUris.Contains(myUri))
        allowedUris.Add(myUri);
}

The last step is to go into the ACS settings (I’m using the AppFabric Labs for ACS,) and add the staging environment to the relying parties list, after it’s been deployed and you’ve got the generated URL for staging.

Is it secure?

Hmm, good question – I think the answer is yes. The host header comes from the client, and I’m not sure whether or how well IIS on Azure validates that this header corresponds to the site actually being accessed. So the potential security weakness would be to request the login page with a spoofed host header, then post back to the site with a forged token, thereby bypassing WIF’s check that the incoming token match a configured allowed Uri. However, I don’t think it would be possible to obtain a forged token that would pass the other security measures in place in the website and the ACS configuration itself.

In any case, it would be simple enough to modify this code to only use host headers for a staging site, which would limit spoofing and get you some security through obscurity (which probably has a lot to do with the GUID dynamic URLs in the first place.)

Tags:

Code

Context switching with jQuery

by Jim Jan 29, 2011 8:38 PM

My current project requires me to make a lot of asynchronous calls with javascript, and even to chain these calls. After a lot of refactoring I’m comfortable with the way I’m handling this, but I spent a while fighting with context and having the ‘this’ keyword point to something different every time I used it.

I’m using jQuery for this project. Part of my solution is to explicitly switch context at certain times; the means of doing this is not immediately obvious, I think, from the jQuery documentation, but it’s simple enough.

Given a context object with a function pointer, some data to pass as an argument, and an object whose context I want to switch to (i.e., that object will be the ‘this’ in the invoked function,) I do this:

var p = $.proxy(context.method, context.reader);
p(context.data);

No claim is generated in policy engine

by Jim Jan 24, 2011 8:12 AM

In setting up my azure web role for use with Access Control Services, I get this error, which doesn’t turn up anything in the search engines.

s5t4uq3o

My interpretation of this is that ACS doesn’t have sufficient information to create claims from the identity provider(s).

I solved this problem by configuring rule groups for my relying party. In the AppFabric labs portal, choose ‘Relying party applications.’

buw5txhf

I’ve set up my local machine as a relying party for testing locally, so I choose this, then check the ‘Create new rule group’ box, and click save:

d0nx02v0

I’m bounced back to the list of relying party applications; choose the application again, then click the new ‘Default rule group for…’ link:

image

There are no rules defined for this new group. Click ‘Generate rules,’ then click the ‘Generate’ button to create rules for all identity providers. You should now see a big list of generated rules, and the ‘No claim is generated in policy engine’ should go away. On to the next error!

image

Tags:

Code

Parse a little-endian

by jim Jan 01, 2011 3:44 PM
littleindian

What? No, e-n-d-i-a-n. In the computer world, it’s not unusual to find integers represented in reverse byte order, with the least significant digit first. For example, the hex representation FF01 might be two very different numbers, depending on whether it is big-endian (the way we’re used to seeing them in base 10):

base 16:            FF    01
base 10:           255   001
times position:    2^8   2^0
add to get int:  65280 +   1  =  65281

or little-endian:

base 16:            FF    01
base 10:           255   001
times position:    2^0   2^8
add to get int:    255 + 256  =  511

The javascript parseInt() method assumes a big-endian representation in the string passed to it. Here’s a method that parses a little-endian hex string.

function parseLittleEndian(hex) {
    var result = 0;
    var pow = 0;
    while (hex.length > 0) {
        result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);
        hex = hex.substring(2, hex.length);
        pow += 8;
    }
    return result;
};

Troubleshooting Azure issues

by jim Dec 20, 2010 12:00 PM

This post is a bucket for various issues I’ve run across getting my Azure application working and authentication hooked up. With this new technology, solutions can sometimes be hard to come by.

CommunicationObjectFaultedException

I’ve gotten this exception trying to debug my web role, on more than one occasion.

There are a few causes of this exception documented online, but I’ve found that it can be caused by the general case of any failure to validate the web.config file. For instance, an invalid tag or attribute value can trigger this. 

<foo></foo>

or this empty path value in the location tag:

<location path="">
System.ServiceModel.CommunicationObjectFaultedException was unhandled
  Message=The communication object, System.ServiceModel.Channels.ServiceChannel, 
    cannot be used for communication because it is in the Faulted state.
  Source=mscorlib
  StackTrace:
    Server stack trace: 
       at System.ServiceModel.Channels.CommunicationObject.Close(TimeSpan timeout)
    Exception rethrown at [0]: 
       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       at System.ServiceModel.ICommunicationObject.Close(TimeSpan timeout)
       at System.ServiceModel.ClientBase`1.System.ServiceModel.ICommunicationObject.Close(TimeSpan timeout)
       at Microsoft.WindowsAzure.Hosts.WaIISHost.Program.Main(String[] args)

AudienceUriValidationFailedException

ID1038: The AudienceRestrictionCondition was not valid because the specified Audience is not present in AudienceUris.

Audience: 'https://127.0.0.1:444/'

Exception Details: Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException: ID1038: The AudienceRestrictionCondition was not valid because the specified Audience is not present in AudienceUris.

This means that the WIF configuration doesn’t list the return address as a valid ‘audience uri.’ In your web.config, add the desired address (the one in the message) to the list:

<microsoft.identityModel>
  <service>
    <audienceUris>
      <add value="https://127.0.0.1:8080/" />
      <add value="https://127.0.0.1:444/" />
      <add value="https://casestudy.cloudapp.net/" />
    </audienceUris>

You can have more than one value in here, but I suppose the most secure solution for a production deployment is to limit the list to the necessary value(s).

Another solution is to turn off the check altogether:

<audienceUris mode="Never">

But wait, what about a staging deployment? We don’t know the URL until we’ve deployed, and at that point we can't enter the value in our web.config!

Am I doing this wrong? Do the MS example and see if it works in staging with ACS and the guid address.

No response at all?

imageimageAre you using certificates? If the configuration of the cert or endpoint is set up wrong, you may get a generic “Internet Explorer cannot display the webpage” error.

  On the other hand, if there is no http endpoint configured and you try to access the site with http, you’ll get a “web server refused the connection, ” “10061: Connection refused.”

In the latter case, it’s probably best to configure the http endpoint and have a default, unencrypted landing page, if you’ve got a public site.

The certificate name doesn’t matter in the configuration files, as long as it’s the same in the various places where it’s referenced in configuration. In the service definition file, it should look like this:

<Certificates>
  <Certificate name="MySSLCert" storeLocation="LocalMachine" storeName="My" />
</Certificates>

The store location is important! However the cert is found not by name but by thumbprint; this is specified in the service configuration file:

<Certificates>
  <Certificate 
    name="MySSLCert" 
    thumbprint="4653AE813BA15DFFB027E3AC147004B2D24F472B" 
    thumbprintAlgorithm="sha1" />
</Certificates>

The certificate name is also referenced in the https endpoint configuration.

Issuer of the security token was not recognized

I got this error coming back from authentication, when the browser was redirected to my site.

ID4175: The issuer of the security token was not recognized by the IssuerNameRegistry. To accept security tokens from this issuer, configure the IssuerNameRegistry to return a valid name for this issuer

This means your application is checking the token to ensure that it came from a preconfigured provider, and it can’t find a match. Here’s the relevant section of the web.config file:

<issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuer…">
  <trustedIssuers>
    <add thumbprint="5F7F612950EB8F17FD102F8579EE409C1B81BC5B" 
         name="https://JimACS.accesscontrol.appfabriclabs.com/" />
  </trustedIssuers>
</issuerNameRegistry>

In my case, the AppFabric labs were updated and the certificate thumbprint changed. I couldn’t find a way to obtain the current thumbprint through the ACS management portal.

Warning: this is gonna reset other things in your web.config file, so make sure you’ve got a backup to compare to.

Go through the ‘Add STS Reference’ steps again, with whatever options you used before. This will add an additional trusted issuer to the list in the web.config file, with the correct thumbprint.

NullReferenceException

A common bit of code found in the Azure sample is this block, which switches the cookie encryption to a RSA for compatibility with a web farm (multiple IIS instances.)

List<CookieTransform> sessionTransforms = new
    List<CookieTransform>(new CookieTransform[] { new DeflateCookieTransform(),
    new RsaEncryptionCookieTransform(e.ServiceConfiguration.ServiceCertificate)
    });
var sessionHandler = new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());

e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);

There’s no check to see if the service certificate is configured, which can be done in the web.config file:

      <serviceCertificate>
        <certificateReference x509FindType="FindByThumbprint" findValue="4653AE813B..." />
      </serviceCertificate>

I’ve put the following block of code above the encryption code to give me a meaningful message if the certificate configuration is gone – for instance when rebuilding the ACS connection with the solution explorer’s ‘Add STS Reference’ wizard.

if (e.ServiceConfiguration.ServiceCertificate == null)
{
    throw new ApplicationException("No site certificate; is it set up in web.config?");
    // Make sure you've got the service certificate set up in the web.config:
    // <serviceCertificate>
    //   <certificateReference x509FindType="FindByThumbprint" findValue="4653AE813BA15DFFB027E3AC147004B2D24F472B" />
    // </serviceCertificate>
}

References

Common Windows Identity Foundation WS-Federation Exceptions Explained

Tags:

Code