April 15, 2013 at 1:26 PM

The moment we’ve all been waiting for is finally there.  Windows Azure Infrastructure Services reached the General Availability milestone today.  This contains the following capabilities:

  • Windows Azure Virtual Machines: you are able to have persistent virtual machines deployed in your Windows Azure subscription.  For this, you can bring your own (Linux or Microsoft) images or select them from the existing gallery.
  • Windows Azure Virtual Networking: you are able to provision and manage virtual private networks (VPNs) in Windows Azure and securely connect them with your local IT infrastructure.

More information can be found on the blog of ScottGu: http://weblogs.asp.net/scottgu/archive/2013/04/16/windows-azure-general-availability-of-infrastructure-as-a-service-iaas.aspx

 

What is new with this release ?

There are some interesting new items available with the new release:

  • High memory instances.  These are machines with much more memory assigned to it that can serve some specific workloads.  (these are not the high compute machines.  The names for these machines will be A6 and A7, instead of XXXL Smile)
  • Monthly SLAs.  There will from now on be SLA’s provided, that will measure on a monthly basis.  SLAs for Virtual Machines are 99.95% and require 2 instances.  For Virtual Networking, the monthly SLA will be 99.9%.
  • More validated & supported Microsoft workloads.  There will be much more workloads and images added to the platform.  Also BizTalk Server 2013 will be available soon.
  • The actual prices will start as from June 1, but are seriously decreased, also for PaaS images!

What does it mean for you ?

  • From now on, you are able to have a real better together story that fits your preferences: cloud, on premises or hybrid.
  • You can manage all these machines, using the System Center suite
  • And you can share the same identity management through Active Directory and Federation Services
  • There is no lock in.  This is a common concern for enterprises, but with these infrastructure services, you are now able to move virtual machines from the cloud and run them again in your own data center, because of the VM portability.
  • You can now have both the software and the infrastructure layer provided by the same vendor: Microsoft.  This should help you in getting better quality and support through the wide network of Microsoft partners and local Microsoft teams.

What about BizTalk Server ?

As described in the MSDN article “Configuring BizTalk Server 2013 on a Windows Azure VM”, you can install BizTalk Server in Windows Azure infrastructure services.  Until now, these virtual machines were running in preview mode, meaning they were not officially supported or backed up by SLAs.  But from now on, you can have BizTalk Server officially installed and supported on Windows Azure.

Sam Vanhoutte

Posted in: Azure | BizTalk

Tags: , ,


March 22, 2013 at 10:20 AM

Codit is very happy to let you know that the new version of Microsoft BizTalk Server: BizTalk 2013 has been Released to Manufacturing (RTM).  This version of BizTalk Server is the flagship integration server that is built to build hybrid integration scenarios in an easier and consistent way.

This is the eighth release of BizTalk Server, and it is the eighth version where Codit has been actively working with.  As a TAP customer, we have provided feedback and did extensive testing with the product.  The cloud offerings, which will be released soon, include Infrastructure as a Service (IaaS) capabilities as well as Platform as a Service (PaaS) capabilities. Please stay tuned for exciting updates on this topic in the near future as we are working very close with the product team on these releases.

We are also proud to say that we have just released a new version of the following products, supported and tested on BizTalk Server 2013:

  • Codit Integration Dashboard: handle exceptions and resubmit messages in a user friendly web based portal.
  • Codit Integration Framework: our framework is processing millions of messages every day in projects around the world and will be doing so for the BizTalk 2013 version.  The new version of our framework contains a lot of new features.  Don't hesitate to contact us for more information.

For the on-premises BizTalk Server 2013 release, the following themes are important:

  • Cloud Connectivity
  • Ability to run existing BizTalk applications in the cloud (IaaS)
  • Improved Performance
  • Simplified Development and Management Experience
  • Support for the latest platform and standards

In terms of features, this translates to

  • Integration with Cloud Services- BizTalk Server 2013 includes new out-of-the box adapters to send and receive messages from Windows Azure Service Bus, making it easy to build hybrid solutions. It also provides capabilities to host BizTalk endpoints in Azure through the Service Bus Relay providing a simple and secure way to connect external partners and application to BizTalk Server on premises.
  • RESTful services- BizTalk Server 2013 provides adapters to invoke REST endpoints as well as expose BizTalk Server artifacts as a RESTful service.
  • Enhanced SharePoint adapter- Integrating with SharePoint using BizTalk Server 2013 is now as simple as integrating with a file share.
  • SFTP adapter-Enables sending and receiving messages from an SFTP server.
  • Other enhancements: The ESB capabilities previously introduced in the ESB Toolkit are now fully integrated with BizTalk Server, Dependency tracking,Improvements in dynamic send ports, XslCompiledTransform, more support for protocol updates (X12, EDIFACT, HL7)

There is also a change in the licensing approach, where BizTalk is now moving to a per-core licensing model.  If you need more information on this, don't hesitate to let us know.

Posted in: BizTalk | Service Bus | Azure

Tags:


March 21, 2013 at 3:16 PM

This is the second part in Using ACS and WAAD with JWT Tokens for Web and Store Applications.

If you missed Part 1 make sure you catch up first!

We will first create a Windows Store Application. Then we will make use of the AuthenticationBroker in order to authenticate with our ACS namespace.
To support this type of authentication we will modify our existing MVC application Web Api Controller (created in part 1).

1. Creating the Windows Store Application


If you don't have any experience building Windows Store Applications, there are some things you need to keep in mind:
    - To run / simulate a Windows Store Application, you will need a non-admin user in order to view your application.
    - There is an extra "Simulator" in visual studio that simulates the application instead of deploying it to your Metro interface.


windows_store_vs_simulator

 

1.1. Creating the new project


create_windows_store_project


Add a new javascript file to the solution named "authentication.js". Add the javascript reference to the default.html page.

<script src="/js/authentication.js"></script>

Add a new button and text field in the default.html page by replacing “<p>Content goes here</p>” by:

<p style="margin: 20px;"> 
    <button id="bttnAuthenticate">Login using WAAD</button> 
    <button id="bttnCall">Hit MVC without a token</button> 
    <button id="bttnTokenCall">Hit MVC with Jason Web token</button> 
    <br /> 
    <textarea cols="70" rows="10" id="log"></textarea> 
</p>

Let's add an event handler for our button:

Replace args.setPromise(WinJS.UI.processAll()); in the default.js by 
args.setPromise(WinJS.UI.processAll().done(function () { 
    var bttnAuthenticate = document.getElementById("bttnAuthenticate"); 
    var bttnCall = document.getElementById("bttnCall"); 
    var bttnTokenCall = document.getElementById("bttnTokenCall"); 
    bttnAuthenticate.addEventListener("click", bttnAuthenticateClick, false); 
    bttnCall.addEventListener("click", bttnCallClick, false); 
    bttnTokenCall.addEventListener("click", bttnTokenCallClick, false); 
}));

 

1.2. Modifying our existing Auth Api Controller


In the GetToken method we currently have the following:

[AllowAnonymous] 
[HttpPost] 
public HttpResponseMessage GetToken() 
{ 
    var response = Request.CreateResponse(HttpStatusCode.Redirect); 
    response.Headers.Add("Location", "/"); 
    return response; 
}

 

In order to pass the token to a Windows Store Apps we need to adjust the GetToken method to the following;

[HttpPost] 
[AllowAnonymous] 
public HttpResponseMessage GetToken() 
{ 
    var response = Request.CreateResponse(HttpStatusCode.Redirect); 
    var bootstrapToken = ExtractBootstrapToken(); 
    const string mvcCookieName = "tokenCookie"; 
    // We check for cookies here. If there is no "login" cookie we do not issue a token redirect (for use in Windows Store Apps) 
    if (HttpContext.Current.Request.Cookies.AllKeys.Contains(mvcCookieName)) 
    { 
        response.Headers.Add("Location", string.Format("/")); 
    } 
    else 
    { 
        response.Headers.Add("Location", string.Format("/auth/end?t={0}", bootstrapToken)); 
    } 
    return response; 
}

protected virtual string ExtractBootstrapToken() 
{ 
    var bc = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext; 
    return  ((JWTSecurityToken) bc.SecurityToken).RawData; 
}

 

Let's explain what's changed:
Whenever a request comes in that triggers an action method on any of our Web Api controllers, we will need to provide a token. Whether this request is coming from our current MVC Application or our Windows Store Application.
When we login to MVC, we need to redirect the user to the homepage.
When we login to Windows Store Application, we need to redirect to a Url that is configured in our store application as return Url for the Authentication Broker. (see later)
The redirection Url will also contain the token as a querystring.

The only way (that I know of) we can do this is by setting a cookie on the client that is included in the request when we login from MVC. The store application will not provide any cookies so we will get our custom return Url.
Setting the cookie is easy by adding the following to our Authentication Controller Login Action:

ControllerContext.HttpContext.Response.Cookies.Add(new HttpCookie("tokenCookie") { Value = "" });

 

1.3. Configuring the authentication broker

 

Great, our superfantastic GUI is all setup and our controller will redirect us to a custom URI. Time to add some javascript to start our login process. To achieve that, we will make use of the Authentication Broker

Add the following code to the authentication.js file:

function bttnAuthenticateClick() { 
    var log = document.getElementById("log");

    var requestUri = "https://[yourAcsNamespace].accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&wtrealm=[yourRealm]"; 
    // Add the url here that you redirect to in the Auth Api Controller 
    var callBackUri = "[yourRedirectUrl]";

    if (authzInProgress) { 
        log.value = "Authorization already in Progress ..."; 
        return; 
    }

    var startUri = new Windows.Foundation.Uri(requestUri); 
    var endUri = new Windows.Foundation.Uri(callBackUri);

    log.value = "Navigating to: " + requestUri + "\r\n";

    authzInProgress = true;

    Windows.Security.Authentication.Web.WebAuthenticationBroker.authenticateAsync( 
        Windows.Security.Authentication.Web.WebAuthenticationOptions.none, startUri, endUri) 
        .done(function (result) { 
            log.value += "Response Data | Status: " + result.responseData + "|" + result.responseStatus + "\r\n";

            if (result.responseStatus === Windows.Security.Authentication.Web.WebAuthenticationStatus.errorHttp) { 
                log.value += "Error returned: " + result.responseErrorDetail + "\r\n"; 
            }

            if (result.responseData.split('?')) { 
                token = result.responseData.split('?')[1].split('t=')[1]; 
                log.value += "JWT: " + token + "\r\n"; 
            } else {

            } log.value += "JWT token is missing... something went wrong \r\n";

            authzInProgress = false; 
        }, function (err) { 
            log.value += "Error returned by WebAuth broker: " + err; 
            log.value += "Error Message: " + err.message + "\r\n"; 
            authzInProgress = false; 
        }); 
}



Replace the following values

 

1.3.1. Debugging the authentication broker

We all know that things mostly won't work the first try. When the authentication broker doesn't work, you won't get a proper error message.
That's why we first want to check if our reply Url gets hit by adding a breakpoint. If that breakpoint doesn't get hit, there is a big chance you have a misconfiguration in ACS.

The return Url configured in ACS will trigger our MVC application. The MVC application will get us the token and we'll forward the call to a new Url, the Url defined in our Windows Store Application as "callbackUri".
This Url doesn't need to exist, it will only trigger the callback of the authentication broker.

 

1.4. Running the applications

Fire up another instance of Visual Studio (run as administrator) and open our MVC solution we created in part 1. 
Add a breakpoint to the GetToken method of our Auth Api Controller. Debug the MVC Application.
Run the Simulator to start our windows store application. Click the "Login using WAAD" button.
You should be prompted with the following screen


simulator_waad_authentication

After login, we can debug our GetToken() method:

extract_bootstraptoken

When everything went well, our Windows Store App will be able to retrieve the token

reply_from_mvc

 

2. Secure our Mvc Web Api

2.1. Modifying Global.asax for authentication


Whenever a request comes to trigger an action on one of our Web Api Controllers, we need to parse the JWT Token in order to authenticate the user.
Authentication happens in the Global.asax, authorization will happen in the Controller Action by decorating the class or method with an Authorization Attribute.

To intercept a Web Api request we can make use of the Web Api Message Handlers

Add the following to the Global.asax.cs:

public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            Configure(GlobalConfiguration.Configuration);
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
        }

        static void Configure(HttpConfiguration config)
        {
            config.MessageHandlers.Add(new JwtTokenValidationHandler());
        }

        internal class JwtTokenValidationHandler : DelegatingHandler
        {
            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                // We support Forms Based authentication
                var authCookie = request.Headers.GetCookies(FormsAuthentication.FormsCookieName).FirstOrDefault();
                if (authCookie != null)
                {
                    var authC = authCookie[FormsAuthentication.FormsCookieName];
                    ParseCookie(authC.Value);

                    return base.SendAsync(request, cancellationToken);
                }

                // We support JWT Token authentication
                HttpStatusCode statusCode;
                string token;
                if (!TryRetrieveToken(request, out token))
                {
                    // if the token could not get parsed we still allow access to our controller action methods.
                    return base.SendAsync(request, cancellationToken);
                }

                try
                {
                    var tokenHandler = new JWTSecurityTokenHandler();

                    List<SecurityKey> skeys;

                    var identityConfig = new IdentityConfiguration();
                    string keyName = identityConfig.AudienceRestriction.AllowedAudienceUris[0].ToString();

                    if (((NamedKeyIssuerTokenResolver)(identityConfig).IssuerTokenResolver).SecurityKeys.TryGetValue(keyName, out skeys))
                    {
                        var tok = new NamedKeySecurityToken(keyName, skeys);
                        var validationParameters = new TokenValidationParameters
                        {
                            AllowedAudience = keyName,
                            ValidIssuer = ((ConfigurationBasedIssuerNameRegistry)identityConfig.IssuerNameRegistry).ConfiguredTrustedIssuers.ToList()[0].Value,
                            SigningToken = tok
                        };

                        var currentPrincipal = tokenHandler.ValidateToken(token, validationParameters);

                        Thread.CurrentPrincipal = currentPrincipal;
                    }

                    return base.SendAsync(request, cancellationToken);
                }
                catch (SecurityTokenValidationException)
                {
                    return base.SendAsync(request, cancellationToken);
                }

                catch (Exception ex)
                {
                    statusCode = HttpStatusCode.InternalServerError;
                    // TODO log exception
                }
                return Task<HttpResponseMessage>.Factory.StartNew(() =>
                                                                  new HttpResponseMessage(statusCode));
            }

            private static void ParseCookie(string cookieValue)
            {
                // Parse authentication Cookie here
                FormsAuthenticationTicket enabledTicket = FormsAuthentication.Decrypt(cookieValue);

                if (enabledTicket == null) return;

                var id = new FormsIdentity(enabledTicket);
                var principal = new GenericPrincipal(id, null);
                HttpContext.Current.User = principal;
            }

            private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
            {
                token = null;

                // Substract the token from the bearer authorization header
                IEnumerable<string> authzHeaders;
                if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
                {
                    return false;
                }
                var bearerToken = authzHeaders.ElementAt(0);
                token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
                return true;
            }
        }
    }

 

You don't need to change anything, it will retrieve everything all security settings from the Web.Config.
What we try to do here is set a CurrentPrincipal when we can. When we find an authentication cookie, we parse that cookie (we support forms authentication on MVC). When we find an authentication header, we retrieve the token from the header and try to validate it. If it's valid, we know the current user.
Of course it can happen that the cookie or the authentication header is invalid. However, as we are only authenticating here, we still let the call go through to the controller action. Our controller will check if the user is authenticated or not. Why do we do this? Well, we still need some anonymous actions to be accessible for unauthenticated users.

 

2.2. Adding a Web Api AuthorizationAttrubute

We already added a MultipleAuthorization Attribute for our normal Controllers. Now it's time to add an ApiAuthorizationAttribute for our Api Controllers.

Let's create a new class called "ApiAuthorization" and add the following code

using System.Security.Principal; 
using System.Threading; 
using System.Web.Http.Controllers;

namespace Codit.Blog.Waad.Mvc.Infrastructure.Auth 
{ 
    public class ApiAuthorizeAttribute : System.Web.Http.AuthorizeAttribute 
    { 
        protected override bool IsAuthorized(HttpActionContext context) 
        { 
            IPrincipal client = Thread.CurrentPrincipal; 
            return client.Identity.IsAuthenticated; 
        } 
    } 
}

 

We also add a new Api Controller called "QuoteController" with the following code:

using System.Web.Http; 
using Codit.Blog.Waad.Mvc.Infrastructure.Auth;

namespace Codit.Blog.Waad.Mvc.Controllers.api 
{ 
    public class QuoteController : ApiController 
    { 
        [ApiAuthorize] 
        public string GetSecretQuote() 
        { 
            return "Housework can't kill you, but why take a chance?"; 
        } 
    } 
}

 

We implement our other buttons onclick event handlers:

function bttnCallClick() { 
    WinJS.xhr({ 
        url: 'http://localhost:50238/api/quote/GetSecretQuote', 
        type: 'GET' 
    }).then( 
        function (response) { 
            var log = document.getElementById("log"); 
            log.value = "bttnCall response \r\n"; 
            var json = JSON.parse(response.responseText); 
            log.value += json; 
        }, 
        function(error) { 
            var log = document.getElementById("log"); 
            log.value = "Error in call " + error; 
        }, 
        function (progress) { 
        } 
); 
}

Basically we're requesting the quote but as we're not logged in, our ApiAuthorization class will revoke authorization.

hit_mvc_without_jwt

 

function bttnTokenCallClick() { 
    WinJS.xhr({ 
        url: 'http://localhost:50238/api/quote/GetSecretQuote', 
        type: 'GET', 
        headers: { 
            "Authorization": "Bearer " + token 
        } 
    }).then( 
        function(response) { 
            var log = document.getElementById("log"); 
            log.value = "bttnCall response \r\n";

            var json = JSON.parse(response.responseText); 
            log.value += json; 
        }, 
        function(error) { 
            var log = document.getElementById("log"); 
            log.value = "Error in token call " + error; 
        }, 
        function(progress) { 
        } 
    ); 
};

 

Here we add the token to our Authorization header so it will get parsed in our Global.asax file.
hit_mvc_with_jwt

 

We could extend this example to add more in depth user role authentication but we simply need to call the GraphApi for this.

I hope you enjoyed this series. As you have already seen, there is a lot of configuration to do in order to configure ACS and WAAD. But, with a lot of trial and error you will get a better understanding on how things work.

Download part 2 of this series, the zip contains the Windows Store Application and an updated MVC Application.

Posted in: Azure | WIF

Tags: , ,


March 19, 2013 at 3:39 PM

The purpose of this blog post is to give you a complete overview on how to configure Windows Azure Active Directory (WAAD) together with Windows Azure Access Control Service (ACS). We will create 2 applications (an MVC 4 Web application and a Windows Store Application).

In our MVC application we will support Forms Based Authentication and Claims Based Authentication at the same time.

In our Windows Store Application we will use the JWT token generated by ACS to authenticate on our previously created MVC Web Api controllers.

On both applications we will be able to authorize users based on their roles (CIA users and U.S. Marine users).

 

This blog post will consist of 2 parts:

1. Setting up ACS, WAAD and an MVC Application by using Jason Web Tokens (this part)

2. Add support for Windows Store Applications by passing the Jason Web Token

 

1. Configuration on Windows Azure

Prerequisites

  • .Net Framework 4.5 (Visual Studio 2012)
  • Azure subscription
 

1.1 Configuring WAAD

1. Create / or use an existing WAAD account (our sample WAAD domain is "natsec"). Sign-up: (https://activedirectory.windowsazure.com/Signup/QuickSignup.aspx?ru=https://activedirectory.windowsazure.com&ali=1)

windows_azure_active_directory_create

2. Login on https://activedirectory.windowsazure.com/

3. From here it is pretty straightforward. You can sync an existing AD with your WAAD or create users / groups manually.

For our sample, I've created the following

            2 groups
                - Central Intelligence Agency 
                - US Marine


            3 users:
                - David Estes (member of Central Intelligence Agency group)
                - Saul Goodman (member of Central Intelligence Agency group)
                - Mike Faber (member of US Marine group)


        windows_azure_active_directory_groups windows_azure_active_directory_users     

 

1.2. Configuring ACS

1. Login to your current Windows Azure Subscription (https://manage.windowsazure.com) 
2. Navigate to Active Directory. Create a new Access Control Namespace and after creation, click on the management link (https://[your_namespace].accesscontrol.windows.net/v2/mgmt/web).

 

1.2.1. Create a new Identity Provider

1. Select WS-Federation Identity provider, click next.

2. Enter a display name, select the Url radio button for WS-Federation metadata and enter

https://accounts.accesscontrol.windows.net/[your_namespace].onmicrosoft.com/FederationMetadata/2007-06/FederationMetadata.xml 

In the above url replace [your_namespace] and browse to it to make sure it works.


azure_access_control_service_identity_provider

 

1.2.2. Create a new Relying Party Application

1. As Realm you type your application realm (free to choose, but must be unique in your ACS). ex. urn:NatSec

2. As Return Url, you enter the Url that your MVC front-end will run on. You can change this later to match with your local IIS Express port. The subpath of this URL will be discussed later in this post (needed to set our cookies and/or JWT token).

3. As Token Format we will choose JWT (Jason Web Token: at time of writing it is still in beta, but currently the most compact token available).

4. Under Authentication Settings we select our Identity Provider we just created and check "Create new rule group".

5. For Token Signing Settings we opt for a new generated Symmetric Key. We work with a symmetric key as a certificate would require the MVC website to have it installed in the Certificate Store. As we will host the website on Windows Azure Websites, we currently can't add the certificate.

azure_access_control_service_add_relying_party

 

 

1.2.3. Changing Default Rule Group

In ACS you can map WAAD Claims to your custom claims. To distinguish user access in our application we could map WAAD User Roles to custom User Roles we can use in our application (Another relying party could map role claims to our same custom format). The only problem we face is that the roles are not included in the claims (claims could become very large). When we need to request the current user roles, we need to query the GraphApi from WAAD. The mapping of user roles will happen on our MVC backend later.

1. Edit the Rule Group and Generate default rules. (this way we will receive standard claims like 'firstname', 'lastname', ... )

In order to please ASP.Net Security we will need to modify an existing claim. ASP.Net AntiForgery expects the following claims to be present:

2. Edit the name claim and change the output claim to "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" (in the predefined selectable types)

change_input_claim

 

1.3. Creating a Trust relation ship between ACS and WAAD

 

Prerequisites

 

WAAD should be configured to trust our ACS to issue a token. The only way we currently can configure this is with PowerShell.

Enter the following statements

connect-msolservice 
import-module msonlineextended –force 
$replyUrl = New-MsolServicePrincipalAddresses -Address "https://[yournamespace].accesscontrol.windows.net/" 
New-MsolServicePrincipal -ServicePrincipalNames @("https://[yournamespace].accesscontrol.windows.net/") -DisplayName "[justAName]" -Addresses $replyUrl

You will be prompted for your WAAD credentials after line 1 (ex. david.estes@natsec.onmicrosoft.com).

On line 3 you'll need to replace [yournamespace] with the namespace you choose for ACS (ex. coditblog)

On line 4 you'll need to replace [yournamespace] with the namespace you choose for ACS (ex. coditblog) and [justAName] with a descriptive name).

waad_acs_trust

Be sure to note the symmetric key credential that is created for you as output of the cmdlet if you do not supply a value. Once the service principal has been created, you cannot retrieve the symmetric key credential. You will need to use it in your code when authenticating to Windows Azure AD Access Control.

 

2. Building our MVC Application

 

2.1. Creating the MVC Application

The MVC Application will act as an API to issue a token for our Windows Store Application. It will contain all configuration in order to authenticate with ACS. 
Create a new MVC Application using an Internet Application as Project Template. 

vs2012_mvc_waad_create_app vs2012_mvc_waad_create_app_project_template 

Most existing applications will already have some security mechanism, so we'll jump into a real-world scenario and use Forms Authentication as our current authentication. We will extend our authentication mechanism by configuring ACS in our application. 
Using the Internet Application Template, Forms Authentication is already configured. Forms Authentication in MVC 4 is no longer using the ASP.Net MembershipProvider but instead it's using SimpleMembership.


        First of all, start the application and Create a new users (default password in the sample is: "mypassword")
        mvc_forms.create_user


Stop the application and click "Show All Files" in Solution Explorer. You will notice the mdf ASP.net Membership database file under "App_Data". Include the file into the project and double click on it.


        For the sake of simplicity, we'll create our roles using T-SQL. Right click the database (in Server Explorer) and select "New Query".
        Execute the following statement:

insert into [aspnet-Codit.Blog.Waad.Mvc-20130301113648].[dbo].[webpages_Roles] (RoleName) values ('CIA') 
insert into [aspnet-Codit.Blog.Waad.Mvc-20130301113648].[dbo].[webpages_Roles] (RoleName) values ('U.S. Marine') 
insert into [aspnet-Codit.Blog.Waad.Mvc-20130301113648].[dbo].[webpages_UsersInRoles] (UserId, RoleId) values (1, 2)

        mvc_simplemembership_configure_roles


        As you may have noticed already, the roles are different from the roles we previously configured in WAAD. This is on purpose.

 

2.2. Configuring ACS in our MVC Application

Add the following NuGet Package to your solution: "JSON Web Token Handler For the Microsoft.Net Framework 4.5" (Id: Microsoft.IdentityModel.Token.JWT (https://nuget.org/packages/Microsoft.IdentityModel.Tokens.JWT/0.1.0))

Also add a reference to System.IdentityModel (v4.0.0.0) and System.IdentityModel.Services (v4.0.0.0)


        Create a new class "CustomJwtSecurityTokenHandler"
 

using System.Collections.Generic; 
using System.IdentityModel.Tokens; 
using System.Linq; 
using System.Security.Claims; 
using Microsoft.IdentityModel.Tokens.JWT;

namespace Codit.Blog.Waad.Mvc.Infrastructure.Auth.Handlers 
{ 
	public class CustomJwtSecurityTokenHandler : JWTSecurityTokenHandler 
	{ 
		public override ClaimsPrincipal ValidateToken(JWTSecurityToken jwt, TokenValidationParameters validationParameters) 
		{ 
			if ((validationParameters.ValidIssuer == null) && 
				(validationParameters.ValidIssuers == null || !validationParameters.ValidIssuers.Any())) 
			{ 
				validationParameters.ValidIssuers = new List<string> { ((ConfigurationBasedIssuerNameRegistry)Configuration.IssuerNameRegistry).ConfiguredTrustedIssuers.First().Value }; 
			}

			if (validationParameters.SigningToken == null) 
			{

				var resolver = (NamedKeyIssuerTokenResolver)this.Configuration.IssuerTokenResolver; 
				if (resolver.SecurityKeys != null) 
				{ 
					var keyName = Configuration.AudienceRestriction.AllowedAudienceUris[0].ToString(); 
					List<SecurityKey> skeys; 
					if (resolver.SecurityKeys.TryGetValue(keyName, out skeys)) 
					{ 
						var tok = new NamedKeySecurityToken(keyName, skeys); 
						validationParameters.SigningToken = tok; 
					} 
				} 
			} 
			return base.ValidateToken(jwt, validationParameters); 
		} 
		protected override string NameIdentifierClaimType(JWTSecurityToken jwt) 
		{ 
			return ClaimTypes.GivenName; 
		} 
	} 
}

JWT Token Validation isn't supported out of the box so we override the ValidateToken method. The main issue is that the parameters defined in the config aren't recognized so we need to read them from the config ourselves.

We do an override of the NameIdentifierClaimType method in order to pass our name claim to be set in the RolePrincipal object. By default it will use the "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" claim. This claim contains our user's complete e-mail adress. Instead we want to greet the user with his first name. We return the default nameclaim ClaimTypes.GivenName (="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"). The result of this override is demonstrated in the following screenshot


        waad_claims_roleprincipal

 


        Next add the following configuration to your Web.Config
     

<system.identityModel> 
<identityConfiguration saveBootstrapContext="true"> 
  <audienceUris> 
	<add value="[yourRealm]" /> 
  </audienceUris> 
  <securityTokenHandlers> 
	<add type="[yourClassAndAssemblyCustomJWTTokenHandler]" /> 
	<securityTokenHandlerConfiguration> 
	  <certificateValidation certificateValidationMode="PeerTrust" /> 
	  <issuerTokenResolver type="[yourClassAndAssemblyCustomJWTTokenHandler]"> 
		<securityKey symmetricKey="[jwtSymmetricKey]" name="[yourRealm]" /> 
	  </issuerTokenResolver> 
	</securityTokenHandlerConfiguration> 
  </securityTokenHandlers> 
  <issuerNameRegistry type="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
	<trustedIssuers> 
	  <add thumbprint="[thumbPrint]" name="https://[yournamespace].accesscontrol.windows.net/" /> 
	</trustedIssuers> 
  </issuerNameRegistry> 
</identityConfiguration> 
</system.identityModel> 
<system.identityModel.services> 
<federationConfiguration> 
  <cookieHandler requireSsl="false" /> 
  <wsFederation passiveRedirectEnabled="true" issuer="https://[yournamespace].accesscontrol.windows.net/v2/wsfederation" realm="[yourRealm]" requireHttps="false" /> 
</federationConfiguration> 
</system.identityModel.services>

On line 2:

We've added saveBootstrapContext="true" in order to retrieve our JWT token easily in our controller.

On line 4:

Replace [yourRealm] with the realm you entered when creating a relying party (ex. urn:NatSec)

On line 7:

Replace [yourClassAndAssemblyCustomJWTTokenHandler] with the your "custom jwt class, assemblyname".

On line 10:

Replace [yourClassAndAssemblyCustomJWTTokenHandler] with the your "custom jwt class, assemblyname".

On line 11:

Replace [yourRealm] with the realm you entered when creating a relying party (ex. urn:NatSec)

On line 11:

Replace [jwtSymmetricKey] with the symmetric key of your JWT (ACS Management page => Certificates and keys => Token Signing => [your RP] (WAAD - NatSec) => Copy the full 256-bit symmetric key

On line 17: 

Replace [thumbPrint] with your Service Certificate Thumbprint (ACS Management page => Service Settings => Certificates and keys => Token Signing => Service Namespace (X.509 Certificate) => Copy your thumbprint).

Replace [yournamespace] with your ACS namespace (ex. coditblog)

On line 25:

Replace [yournamespace] with your ACS namespace (ex. coditblog)

Replace [yourRealm] with the realm you entered when creating a relying party (ex. urn:NatSec)


        Add requestValidationMode="4.5" to the httpRuntime element.
      

<httpRuntime targetFramework="4.5" requestValidationMode="4.5" />


        Add <allow users="*" /> as a child of the <authorization> element and above the <deny users="?" /> element.

<authorization>
  <allow users="*"/>
  <deny users="?" />
</authorization>


        Make sure any wif packages do not disable forms authentication module (comment the remove element if you have it)

<system.webServer>
<modules>
      <!--<remove name="FormsAuthentication" />-->
</modules>
</system.webServer>

 

When you run the application you will be automatically promted with the following screen:  
waad_sign_in

 

 

2.3. Support ACS and Forms Authentication

In order to allow Forms Based login, we need to disable the auto redirect to the Windows Azure Active Directory login page. We can do this by setting "passiveRedirectEnabled" to false in our web.config (wsFederation element). 
When we now run the application we can use the standard Forms Authentication but the WAAD seems to be disabled. We need to manually add a link in order for the user to login using WAAD.
We will and cannot use the build in Authentication Providers class for this demo. Instead locate the following line in Login.cshtml
      

@Html.Action("ExternalLoginsList", new { ReturnUrl = ViewBag.ReturnUrl })


and replace it with

<a href="https://[yournamespace].accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&wtrealm=[yourRealm]" title="Log in using your Windows Azure Active Directory account">Windows Azure Active Directory</button>

Make sure you replace the following in the above URL

    • [yourRealm] with the realm you entered when creating a relying party (ex. urn:NatSec) 
    • Replace [yournamespace] with your ACS namespace (ex. coditblog)  
 

waad_login_option


        In order to authenticate successfully with our ACS we need to make sure we support the configured Return Url (in ACS).

We will create a new WebApi controller to act as our return Url. You could also use a normal controller but our WebApi controller will become in handy when we also support Windows Store Applications. We use WebAPI for returning tokens and JSON data, we will use normal Controllers for returning Views. Create a new folder named "api" under "Controllers". Add a new Empty Web API Controller named "AuthController".

 

        empty_web_api_controller


Add the following
      

using System.Net; 
using System.Net.Http; 
using System.Web.Http;

namespace Codit.Blog.Waad.Mvc.Controllers.api 
{ 
	public class AuthController : ApiController 
	{ 
		[AllowAnonymous] 
		[HttpPost] 
		public HttpResponseMessage GetToken() 
		{ 
			var response = Request.CreateResponse(HttpStatusCode.Redirect); 
			response.Headers.Add("Location", "/"); 
			return response; 
		} 
	} 
}


When the return url is configured correctly in ACS, then this controller action will be called after the login procedure of WAAD.
It will receive a HttpPost with security tokens, these tokens will result in FedAuth cookies.


Fiddler Return Url request from WAAD:

fiddler_token_response


Fiddler Cookies on Redirect to home page:

fiddler_fedauth_cookies

 

And we're in: 

waad_login_success

 

 

 

2.4. Enabling WAAD Graph Api and Role Authentorization

We've already discussed authentication before, now it is time for authorization. Based on the roles of a user we will allow or deny page requests.

 

2.4.1. References and Packages

Add the following NuGet Package Windows Azure Authentication Library (Beta) to your solution

Id: Microsoft.WindowsAzure.ActiveDirectory.Authentication (https://nuget.org/packages/Microsoft.WindowsAzure.ActiveDirectory.Authentication/0.6.1)

Add a service reference to your WAAD using the following URL: https://graph.windows.net/[yourWaadDomain]

Replace [yourWaadDomain] by your Waad Domain (obviously...) ex. NatSec

Reference following assemblies:

System.Windows.Forms (v4.0.0.0)

 

In order to access the GraphApi, we need to give read-permissions. Fire up a PowerShell instance and enter following commands.

First of all we need to retrieve the RoleMemberObjectId (so it can be replaced in the next command), type the following command:

Get-MsolServicePrincipal | select DisplayName,ObjectId

 

After executing the command below we will have read-only access to the WAAD Directory. 

Add-MsolRoleMember -RoleName "Service Support Administrator" -RoleMemberType ServicePrincipal -RoleMemberObjectId [yourRoleMemberObjectId]

 

2.4.2. Interaction with the GraphApi

Add a new class named "GraphClient" (see inline for detailed explanations)

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using Codit.Blog.Waad.Mvc.NatSec.Microsoft.WindowsAzure.ActiveDirectory;

using Microsoft.WindowsAzure.ActiveDirectory.Authentication;



namespace Codit.Blog.Waad.Mvc.Infrastructure.Auth.GraphApi

{

    /// <summary>

    /// This class uses the Windows Azure Graph API to retrieve a given user's direct group memberships.

    /// Except for the <see cref="GetUserGroups"/> method, the code in this class is heavily based on public

    /// Graph API examples from Microsoft.

    /// </summary>

    public class GraphClient

    {

        private readonly DirectoryDataService _dataService;

        private readonly string _tenantDomainName;

        private readonly string _servicePrincipalSymmetricKey;

        private readonly string _tenantId;

        private readonly string _appPrincipalId;



        // ReSharper disable InconsistentNaming

        /// <summary>

        /// Name of the HTTP header that contains the unique ID of a client request.

        /// Used when making Graph API requests

        /// </summary>

        private const string HeaderName_ClientRequestId = "client-request-id";



        /// <summary>

        /// Authorization header used when making Graph API requests

        /// </summary>

        private const string HeaderName_Authorization = "Authorization";



        /// <summary>

        /// Version of the data contract, used when making Graph API requests

        /// </summary>

        private const string HeaderName_DataContractVersion = "x-ms-dirapi-data-contract-version";

        // ReSharper restore InconsistentNaming



        private const string DataContractVersion = "0.8";



        public GraphClient(string tenantDomainName, string tenantId, string appPrincipalId, string servicePrincipalSymmetricKey)

        {

            _tenantDomainName = tenantDomainName;

            _tenantId = tenantId;

            _servicePrincipalSymmetricKey = servicePrincipalSymmetricKey;

            _appPrincipalId = appPrincipalId;



            _dataService = new DirectoryDataService(GetConnectionUri());

            _dataService.SendingRequest += (sender, args) =>

            {

                var webRequest = ((HttpWebRequest)args.Request);

                webRequest.Headers.Add(HeaderName_Authorization, GetAuthorizationHeader());

                webRequest.Headers.Add(HeaderName_DataContractVersion, DataContractVersion);

                webRequest.Headers.Add(HeaderName_ClientRequestId, Guid.NewGuid().ToString());

            };

        }



        /// <summary>

        /// Identifier of the issuing resource for the symmetric key.

        /// Used for getting an access token for requests.

        /// Looks something like this:

        /// A4423C7C-35F7-4679-99F8-5921A0482B63@tenantdomain.onmicrosoft.com

        /// (the GUID here is an example, not the actual value)

        /// </summary>

        private string GetSymmetricKeyIssuingResource()

        {

            return _appPrincipalId + "@" + _tenantDomainName;

        }



        /// <summary>

        /// Realm identifier for the service we want to access. Which is the tenant domain

        /// hosted at Windows Azure AD.

        /// 00000002-0000-0000-c000-000000000000/graph.windows.net@yourtenantdomain.onmicrosoft.com

        /// (the GUID here is the actual identifier)

        /// </summary>

        private string GetServiceRealm()

        {

            return AzureAdPrincipalId + "/" + GraphApiServiceHost + "@" + _tenantDomainName;

        }



        /// <summary>

        /// URI of the Graph API we're accessing.

        /// Looks something like this:

        /// https://graph.windows.net/EA314D90-8751-4534-A96E-77A5DF0E72AB

        /// (the GUID here is an example, not the actual value)

        /// </summary>

        private Uri GetConnectionUri()

        {

            return new Uri(string.Format(@"https://{0}/{1}", GraphApiServiceHost, _tenantId));

        }



        /// <summary>

        /// URI of the WAAD tenant domain.

        /// Looks something like this:

        /// https://accounts.accesscontrol.windows.net/yourtenantdomain.onmicrosoft.com

        /// </summary>

        private string GetFullTenantUri()

        {

            return "https://accounts.accesscontrol.windows.net/" + _tenantDomainName;

        }



        /// <summary>

        /// This is the known identifier of the WAAD service principal

        /// </summary>

        private const string AzureAdPrincipalId = "00000002-0000-0000-c000-000000000000";



        /// <summary>

        /// This is the domain name of the WAAD Graph API service

        /// </summary>

        private const string GraphApiServiceHost = "graph.windows.net";



        /// <summary>

        /// Method to get the Oauth2 Authorization header from WAAD. This basically authenticates

        /// the calling application to WAAD and gets a token with which further requests can be made.

        /// </summary>

        private string GetAuthorizationHeader()

        {

            var authContext = new AuthenticationContext(GetFullTenantUri());

            var credential = new SymmetricKeyCredential(GetSymmetricKeyIssuingResource(), Convert.FromBase64String(_servicePrincipalSymmetricKey));

            AssertionCredential assertionCredential = authContext.AcquireToken(GetServiceRealm(), credential);

            return assertionCredential.CreateAuthorizationHeader();

        }



        /// <summary>

        /// Queries the Graph API for security groups in which an active user with the given

        /// <paramref name="userPrincipalName"/> is a direct member.

        /// </summary>

        public IList<Group> GetUserGroups(string userPrincipalName)

        {

            var user = _dataService.Users

                .Where(u => u.AccountEnabled == true && u.UserPrincipalName == userPrincipalName)

                .AsEnumerable()

                .SingleOrDefault();



            var groupReferences = _dataService.LoadProperty(user, "MemberOf")

                .OfType<ReferencedObject>()

                .Where(r => r.ObjectType == "Group")

                .Select(g => g.ObjectId);



            return _dataService.Groups

                .AsEnumerable()

                .Where(g => groupReferences.Contains(g.ObjectId))

                .ToList();

        }

    }

}

 

Add a new class named GraphApiClaimAuthenticationManager (will use the GraphApi class)

Please replace [yourSymmetricKey] and [appPrincipalId] with the values you received when creating your WAAD using powershell.

Please see inline for detailed explanation. 

using System.Collections.Generic;

using System.Linq;

using System.Security.Claims;

using System.Web.Http;

using Codit.Blog.Waad.Mvc.Infrastructure.Auth.GraphApi;



namespace Codit.Blog.Waad.Mvc.Infrastructure.Auth.GraphApi

{

    /// <summary>

    /// This class uses <see cref="GraphClient"/> to read the AD security groups in which a given

    /// <see cref="ClaimsPrincipal"/> is a direct member and then converts the memberships to group

    /// claims. The group claims are then used to authorize user actions with <see cref="AuthorizeAttribute"/>.

    /// </summary>

    public class GraphApiClaimAuthenticationManager : ClaimsAuthenticationManager

    {

        /// <summary>

        /// This is an arbitrary string identifying the claims issued by this class.

        /// It exists to make it possible to distinguish those claims from other claims.

        /// </summary>

        private const string ClaimIssuerName = "waad-demo-usergroup-roleclaim";



        /// <summary>

        /// Augument <paramref name="incomingPrincipal"/> with claims obtained by converting

        /// the user's direct security group memberships to role claims.

        /// </summary>

        public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)

        {

            if (incomingPrincipal == null || !incomingPrincipal.Identity.IsAuthenticated)

                return incomingPrincipal;



            // TODO: Load user roles from cache to avoid roundtrips to GraphApi

            // TODO: Load these keys from persistence store based on the tenantDomain

            const string appPrincipalId = "[yourAppPrincipalId]";

            const string symmKey = "[yourSymmetricKey]";

            var upn = incomingPrincipal.FindFirst(ClaimTypes.Upn).Value;

            var tenantId = incomingPrincipal.FindFirst("http://schemas.microsoft.com/ws/2012/10/identity/claims/tenantid").Value;

            var tenantDomain = upn.Split('@')[1];



            var graphClient = new GraphClient(tenantDomain, tenantId, appPrincipalId, symmKey);

            var userGroups = graphClient.GetUserGroups(upn);



            var localRoles = new List<string>();

            // Our local roles are CIA and U.S. Marine

            // The roles on WAAD are Central Intelligence Agency and US Marine

            // TODO: load these from persistence store

            foreach (var userGroup in userGroups)

            {

                switch (userGroup.DisplayName)

                {

                    case "Central Intelligence Agency":

                        localRoles.Add("CIA");

                        break;

                    case "US Marine":

                        localRoles.Add("U.S. Marine");

                        break;

                }

            }



            var roleClaims = localRoles.Select(x => new Claim(ClaimTypes.Role, x, null, ClaimIssuerName));



            ((ClaimsIdentity)incomingPrincipal.Identity).AddClaims(roleClaims);



            return incomingPrincipal;

        }

    }

}

 

There are a couple of things that can do here in order to extend functionality. If we support multiple WAAD tenants, we could load the securitykeys based on the waad domain from a persistence store.

We could also store mapping roles in our persistence store in order to configure them later. As noted before, roles of WAAD aren't the roles you will use locally.

 

In order to use the GraphApiClaimAuthenticationManager we need to add an extra line in our config that is responsible for kicking in our Authentication Manager

<claimsAuthenticationManager type="[NamespaceAndClassOfAuthManager], [assemblyName]" />

 

We would like to restrict access to our Contact page for US Marines. So only our CIA personnel will be authorized to access the contact page.

Protect our controller by replacing our Controller Action in HomeController.cs. The MultipleAuthorize class decoration is discussed later.

[MultipleAuthorize(Roles = "CIA")]

public ActionResult Contact()

{

	ViewBag.Message = "CIA Only!";



	return View();

}

 

Normally we could make use of the IsInRole method exposed by ClaimsPrincipal. However, I never succeeded on using this when we have Claims Based and Forms Based Authentication enabled. It will always falls back to Forms Based Authentication by default.

Therefore, I've implemented a custom authorization attribute that will check for claims and roles manually.

using System.Linq;

using System.Security.Claims;

using System.Security.Principal;

using System.Threading;

using System.Web.Mvc;



namespace Codit.Blog.Waad.Mvc.Infrastructure.Auth

{

    public class MultipleAuthorize : AuthorizeAttribute

    {

        protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)

        {

            IPrincipal client = Thread.CurrentPrincipal;



            // Customer ClaimsIdentity authorization

            if ((client.Identity.GetType() == typeof (ClaimsIdentity)))

            {

                if (client.Identity.IsAuthenticated)

                {

                    var roleClaims = ((ClaimsIdentity) client.Identity).Claims.Where(x => x.Type == ClaimTypes.Role).ToList();

                    

                    if (Roles.Split(',').Any(role => roleClaims.FirstOrDefault(x => x.Value == role) == null))

                    {

                        return false;

                    }

                    return true;

                }

                return false;

            }



            // Use normal forms authorization     

            return base.AuthorizeCore(httpContext);

        }

    }

}

 

When you login either using WAAD or Forms authentication, you should be able to access the Contact page when you are part of the CIA and get an Access Denied Exception when you aren't part of the CIA.

You can download the complete sample of this first part here

 

In the next part, we'll add support for Windows Store Applications. Stay tuned!

 

Posted in: Azure | WIF

Tags: , ,


February 6, 2013 at 4:09 PM

When trying to install SQL Server 2008 R2 on a Windows Server 2008 R2 Virtual Machine on Azure, you might come across the following error at the Setup Support Rules step:

 

 

This has to do with two manifest files that are corrupt.

If you have another working installation, you can copy the following two manifest files from the working server to the failing server:

  • C:\Windows\winsxs\Manifests\amd64_microsoft.vc80.atl_1fc8b3b9a1e18e3b_8.0.50727.4053_none_8a1a02152edb659b.manifest
  • C:\Windows\winsxs\Manifests\x86_microsoft.vc80.atl_1fc8b3b9a1e18e3b_8.0.50727.4053_none_d1c738ec43578ea1.manifest

 

If you don’t have another working installation, find and open the files mentioned above and paste the following xml in them:

  • AMD64 Manifest:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <!-- Copyright © 1981-2001 Microsoft Corporation -->
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <noInheritable/>
    <assemblyIdentity type="win32" name="Microsoft.VC80.ATL" version="8.0.50727.4053" processorArchitecture="amd64" publicKeyToken="1fc8b3b9a1e18e3b"/>
    <file name="ATL80.dll" hash="99840dcc34e78af239d80841eba316c184e407cd" hashalg="SHA1"/>
    </assembly>
  • X86 Manifest:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <!-- Copyright © 1981-2001 Microsoft Corporation –>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <noInheritable/>
    <assemblyIdentity type="win32" name="Microsoft.VC80.ATL" version="8.0.50727.4053" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
    <file name="ATL80.dll" hash="6d7ce37b5753aa3f8b6c2c8170011b000bbed2e9" hashalg="SHA1"/>
    </assembly>

 

Note: You probably need to change the permissions for those files to be able to overwrite them.
To do so, go to the file properties, Security tab, Advanced, Owner tab, Edit, Select the Administrators group and click three times OK until all windows are closed.
Reopen the properties for the file, Security tab, Edit, Select the Administrators group and select Full Control.


January 28, 2013 at 2:41 PM

The BizTalk Server 2013 Beta release comes with the SB-Messaging adapter.  This adapter allows our on-premise BizTalk environment to integrate seamlessly with the Windows Azure Service Bus queues, topics and subscriptions.  Together with my colleague Mathieu, I had a look at these new capabilities.

 

Adapter Configuration

The configuration of SB-Messaging receive and send ports is really straightforward.  BizTalk just needs these properties in order to establish a connection to the Azure cloud:

  • Service Bus URL of the queue, topic or subscription:

        sb://<namespace>.servicebus.windows.net/<queue_name>

  • Access Control Service STS URI:

        https://<namespace>-sb.accesscontrol.windows.net/

  • Issuer name and key for the Service Bus Namespace

 

Content Based Routing

Both Service Bus and BizTalk messaging layer offer a publish-subscribe engine, which allows for content based routing.  In BizTalk, content based routing is done through context properties, the Azure Service Bus uses Brokered Message properties.  A BizTalk context property is a combination of the propertyName and propertyNamespace.  In Azure Service Bus, context properties are only defined by a propertyName.  How are these metadata properties passed from the cloud to BizTalk and vice versa?

 

Sending from BizTalk to Service Bus topic

In order to pass context properties to the Service Bus topic, there’s the capability to provide the Namespace for the user defined Brokered Message Properties.  The SB-Messaging send adapter will add all BizTalk context properties from this propertyNamespace as properties to the Brokered Message.  Thereby, white space is ignored.

image

 

Receiving from Service Bus subscription to BizTalk

Also at the receive adapter, there’s the possibility to pass properties to the BizTalk message context.  You can specify the Namespace for Brokered Message Properties, so the SB-Messaging adapter will write (not promote) all Brokered Message properties to the BizTalk message context, within the specified propertyNamespace.  Be aware when checking the option Promote Brokered Message Properties, because this requires that a propertySchema is deployed which contains all Brokered Message properties.

 

image

 

Receive Port Message Handling

I was interested in the error handling when an error occurs in the receive adapter or pipeline.  Will the message be roll backed to the Azure subscription or suspended in BizTalk?  Two fault scenarios were investigated.

 

Receive adapter unable to promote property in BizTalk context

In this case, we configured the receive port to promote the context properties to a propertyNamespace that did not contain all properties of the Brokered Message.  As expected, the BizTalk adapter threw an exception:

  • The adapter "SB-Messaging" raised an error message. Details "System.Exception: Loading property information list by namespace failed or property not found in the list. Verify that the schema is deployed properly.

The adapter retried 10 times in total and moved afterwards the Brokered Message to the dead letter queue of the Service Bus subscription.  Afterwards, BizTalk started processing the next message.

 

Receive pipeline unable to parse message body

In this simulation we tried to receive an invalid XML message with the XMLReceive pipeline.  After the error occurred, we discovered that the message was suspended (persisted) in BizTalk.

 

WCF-Adapter Framework

It’s a pity to see that this new adapter is not implemented as a WCF-binding.  Due to this limitation, we can’t make use of the great extensibility capabilities of the WCF-Custom adapter.  The NetMessagingBinding could be used, but I assume some extensibility will be required in order to transform BizTalk context properties into BrokeredMessageProperty objects and vice versa.  Worthwhile investigating…

 

Conclusion

The BizTalk product team did a great job with the introduction of the SB-Messaging adapter!  It creates a lot of new opportunities for hybrid applications.

Posted in: Azure | BizTalk | Service Bus | WCF

Tags:


November 5, 2012 at 10:50 AM

Microsoft has just released the beta release of BizTalk Server 2013.  The first good news is that the initial name (BizTalk 2010 R2) has changed to BizTalk 2013, indicating it will be a major release, providing longer support to our customers.  The Windows Azure image gallery will also be updated to include BizTalk 2013 beta.

Codit is part of two different TAP programs with the same product team: BizTalk 2013 and the Windows Azure BizTalk Services (earlier known as EAI & EDI services).  We have been testing our Integration Framework for BizTalk Server and our Integration Dashboard for BizTalk Server against this new release and we can say we are ready.

It’s great to see things are moving in the Microsoft integration space.

 

The beta can be downloaded here: http://www.microsoft.com/en-us/download/details.aspx?id=35553 and contains the following capabilities:

  • Integration with Windows Azure Service Bus – these are mainly out-of-the-box adapters for Windows Azure Service Bus (both messaging & relay)
  • Support for REST – seeing the web- & device-world move to a REST-oriented approach, it is a very good thing to see support for REST in BizTalk 2013.  And this is not only for consuming, but also for exposing RESTful services!
  • SFTP adapter – this has been a request for years and it’s with great relief that a true SFTP adapter will be part of BizTalk 2013
  • ESB Toolkit – The ESB toolkit has been one of the most unclear parts of BizTalk since its inception.  From guidance over toolkit and now ending up as part of the product.  The configuration experience is much better, which is already good.
  • Dependency tracking – the administration console now shows the dependencies between artifacts
  • Other changes – enhanced SharePoint adapter, improvements in send ports…
  • Host Integration Server, that comes with your BizTalk license, also has some improvements in the following areas: DB2 integration, TI management, Support for MQ v7.5 & v7.1

Conclusion

What first looked like a pure platform update (aligning with SQL Server 2012, Windows Server 2012, .NET 4.5) now has changed to a big upgrade with a lot of enhancements to the product.  Having a full release is an important sign to the market, meaning support lifecycle for this product is significantly longer.


October 5, 2012 at 4:15 PM

This week I represented Codit at the Windows Server 2012 Launch event in Antwerpen. The Launch event had two separate tracks; a Windows Server track and an Azure track. Remarkable is that even on a Windows Server launch event, half of the sessions was about Azure.

In this post I will go over some nice features of Windows Server 2012 - in my personal point of view. This post is no attempt by any means to list all new features and changes in comparison with previous Windows Server versions.

Metro

The first thing you’ll notice is that even Windows Server 2012 uses the Metro ‘Start’ screen (or should we say Modern UI now?). Because Metro is primarily targeting touch-based devices, at first this feels a little odd for a server, but we will get used to it…

clip_image002

Server Manager

The new Server Manager screen is displayed automatically when you boot up your Windows Server 2012. The new Server Manager was a very pleasant surprise! The Server Manager has a dashboard screen with a ‘tile’ for each server role you added to your Windows Server machine:

clip_image004

Each tile gives an instantaneous overview about the state of that specific feature (IIS, DHCP, DNS, AD FS …). Errors are immediately visible because of the red tile. If you click the ‘events’ link displayed in a tile, you will get all events related to that Windows Server feature – very convenient.

That’s not it yet for the Server Manager, you can add other Windows Servers to this dashboard! This will give you a single screen overview of the state of your Windows Servers! Especially when you don’t have SCOM, this is a very useful feature.

Windows Servers can also be grouped in a Server Group. In this way you can perform operations on the group instead of on each server separately.

AppFabric?

Some people expected to get Windows Server AppFabric out of the box with Windows Server 2012. Guess what, it’s not!
Instead Windows Server 2012 ships with IIS8. IIS8 offers a lot of new features and I was very surprised that there wasn’t a single session about IIS8 during the launch event. IIS8 offers a Central Certificate Store; a shared store to manage your certificates in one place instead of on every node of your server farm.
IIS8 also supports WebSockets. WebSockets provide a full-duplex communication channel between the browser and the Web Server over a TCP connection. WebSockets allow pushing content to web clients without an incoming request from that client first! What is very interesting that all this works over port 80 (the TCP channel starts as a HTTP handshake that is then upgraded). All this enables you to push content to your clients over a TCP connection without modifying firewall settings.

.NET

Out of the box, Windows Server 2012 ships with .NET Framework 4.5. When you need .NET Framework 3.5 SP1 (e.g. for SQL Server 2012) you will have to install it separately. I advise you to do this up front, before installing SQL Server 2012. The SQL Server 2012 Installation Wizard fails when .NET framework 3.5 SP1 is not installed. It fails during installation not during the prerequisites check! This means you will need to go through the SQL Server 2012 Installation Wizard again…

 

 

Peter Borremans


July 16, 2012 at 4:34 PM

The announcement

Because of the launch of the new Office version (read more here), there was also some interesting news for everyone interested in the Microsoft middleware… It was obviously not mentioned during the launch (which was off course consumer oriented), but as part of the new release, there are some interesting infrastructure components that are shipped. The service bus and the workflow team have shipped new bits that are available on premises and will be used by the new SharePoint version. This blog post dives deeper in the bits of the Service Bus for Windows Server.  (read here)

Codit has been actively involved as a TAP (technology adoption program) customer for the Service Bus for Windows Server and we can say that we now have full symmetry for Codit Integration Cloud with Codit Integration Server. The exact same configuration and modules that are running in the cloud are also running on premises, giving our customers the choice to deploy locally, in the cloud or in a hybrid model. 

Symmetry on the Microsoft cloud platform

The past years, we’ve seen Microsoft building a lot of things on the Windows Azure platform that they already had on premises. Some examples:

Cloud On premises
Office 365 Sharepoint & Exchange
CRM Online CRM 2011 Server
SQL Azure SQL Server
Windows Azure Windows Server
AppFabric caching Windows Azure Storage Cache

In all of the above cases, Microsoft brought capabilities (they had running on the Windows Server platform for years) from on premises to their cloud platform. And they always tried to make things as symmetric as possible (especially on the development model). But after reading the recent announcements where they are bringing Azure web sites, virtual machines and the management capabilities on premises (read more here), we now also see the first move in the other direction.  And with the recent Office announcements, Microsoft has also released Service Bus for Windows server, a symmetric on premises version of the powerful Windows Azure Service Bus messaging. This post digs deeper in the details of this beta release, but this move shows that Microsoft wants to be the software company that provides software and services, running on the environment of your choice, in the business model of your choice. This will also give a lot of flexibility to ISV’s and companies with a very distributed environment.

One of the biggest unknowns at this time, is how Microsoft will keep symmetry on server. The release cadence of server products versus cloud based services is just too different. New features are being added to the various services all the time, and they also have to ship to the server installations over time. I’m curious to find out what the release cycle will be for these updates. 

What's in the release

The announced release is the first public beta for Service Bus on Windows Server.  It is called beta 2.  The release of Service Bus for Windows server only contains the messaging capabilities of the Windows Azure Service Bus. This means there are no relaying capabilities (nor an on premises ACS service) added to this version. If you want to learn more about queues & topics/subscriptions, don’t hesitate to read more here:

  • Service Bus Queues (how to)
  • Service Bus Topics (how to)  

Scenarios

This server product can be used in a variety of scenarios.

Durable messaging only scenarios 

If you require to exchange messages in a local, messaging only scenario, you can perfectly use Service Bus for Windows server to deliver messages between applications and services in a durable and reliable fashion.

Store & forward scenarios

The Service Bus for Windows server release contains the possibility to define ForwardTo subscriptions on topics, so that messages that match the subscription of these rules, automatically get forwarded to the defined messaging entity. At this point it’s not possible to configure a ForwardTo that points to a remote entity, but one can work around that by having a subscriber that listens to a local ForwardTo entity and sends these messages to a public entity. 

Distributed scenarios 

A lot of organizations have different business units or plants that need to be interconnected. In a lot of companies (often after mergers and acquisitions), the technology that is used in these different plants is different. Therefore, it could be good to have Service Bus being used as the gateway to exchange messages between the different units, while every unit can use it’s standard of choice (REST, SOAP, .NET, AMQP…) to connect to that gateway. 

Installation

The bits are available in the Web Platform Installer (Service Bus 1.0 beta and Workflow 1.0 beta).

Prerequisites

  • Service Bus for Windows server requires Windows Server 2008 R2 SP1 (x64) or Windows Server 2012 (x64). It also installs on Windows 7.
  • SQL Server is needed to host the different entities & configurations. SQL Server 2008 R2 SP1 and SQL Server 2012 are supported (also with their Express editions)
  • Only Windows Authentication is supported, meaning Active Directory is required in a multi-machine scenario.
  • The Windows Fabric gets installed on the Windows system.

Everything is described in detail in the installation guide. 

Topologies

There are two typical topologies. A third could also be used, when having a dedicated SQL with one Service Bus server.

Single box 

This is perfect for development purposes and light weight installations. Having everything in a single box, still allows to use virtualization to get better availability.

 

 

Farm for high availability 

To get high availability, it is needed to have at least 3 service bus instances, due to the new concepts of the Windows Fabric. This is important, when making estimates or system topologies.

 

Configuration

To configure the Service Bus for Windows server, we needed to use PowerShell in the private beta. The following commands create a new service bus farm with a single server.

$mycert=ConvertTo-SecureString -string <Password> -force –AsPlainText
New-SBFarm -FarmMgmtDBConnectionString "data source=(local);integrated security=true" –CertAutoGenerationKey $mycert
Add-SBHost -certautogenerationkey $mycert -FarmMgmtDBConnectionString "data source=(local); integrated security=true"
Get-SBFarmStatus (shows three services running: Service Bus Gateway, Service Bus Message Broker, FabricHostSvc)

Create a service bus namespace

Creating a namespace happens by using the following statement, providing a administrative user and the name of the namespace.

New-SBNamespace -Name CoditBlog -ManageUsers Administrator

As a result, you can see the following information:

Name                  : CoditBlog   
AddressingScheme      : Path   
CreatedTime           : 10/07/2012 15:21:03   
IssuerName            : CoditBlog   
IssuerUri             : CoditBlog   
ManageUsers           : {Administrator}   
Uri                   :   
ServiceIdentifier     :   
PrimarySymmetricKey   : vnAJ7rHp###REPLACE FOR SECURITY####MOvH8Yk=  
SecondarySymmetricKey :

New features

Check for matching subscriptions with the PreFiltering feature

Everyone who ever tried to build a BizTalk application has to be familiar with the following error description: “Could not find a matching subscription for the message”. This was a very common exception, indicating that a message was delivered to the BizTalk messaging agent, while no one was going to pick up that message. The fact that this error was thrown really made sure we would not lose messages in a black hole.

Looking at the publish & subscribe capabilities that came with Windows Azure Service Bus, this was one of the first things I missed. If you submit a message to a topic that does not have subscriptions that match, the message does not get deadlettered, the client does not get a warning or error code and the message is lost. While in certain scenarios this can be desired, a lot more scenarios would find this dangerous. The good thing is that now we get a choice with the Service Bus Server.

A new feature is available that takes care of this. This is PreFiltering. To enable this, you need to configure this on the TopicDescription. And notice one of the longer property names in the Service Bus object model

nsManager.CreateTopic(new TopicDescription { Path = "PrefilterTopic", EnableFilteringMessagesBeforePublishing = true });

If we now submit a message to this topic that does not have a matching subscription configured, we’re getting the following exception.

Type: Microsoft.ServiceBus.Messaging.NoMatchingSubscriptionException   
Message: There is no matching subscription found for the message with MessageId %1%..TrackingId:%2%,TimeStamp:%3%.

As you can see, we can only configure this on a topic. I would have preferred to get the choice to configure this on the sender level. So that, even when sending to the same topic, the client could decide if he wants to have routing failures checked or not.

The complete sample code for this article can be downloaded at the bottom of this page.

ForwardTo: auto forwarding of messages to another entity

In our scenarios, we sometimes have the need to do archiving or auditing on incoming messages across all topics in our namespace. Until now, we have done that by creating a MatchAllFilter (1=1) on every topic and by creating a consumer for every subscription there. That off course takes up more threads and also more messaging transactions. This new feature is solving this for us. The ForwardTo allows us to define an automatic forwarding (transactional in the same namespace) action to another entity.

It’s important to understand that the subscription with ForwardTo enabled only acts as a ‘passthrough’ subscription and that you cannot read from it. The message automatically gets forwarded to its destination queue or topic. If you want to read from it, you get the following exception:

Can not create a message receiver on an entity with auto-forwarding enabled.

To specify a ForwardTo on a subscription, you need to specify this in the SubscriptionDescription, by setting the ForwardTo string property to the path of the destination entity, as can be found in the following snippet:

nsManager.CreateTopic(new TopicDescription("ForwardToTopic");   
nsManager.CreateSubscription(new SubscriptionDescription("ForwardToTopic", "ForwardAll") {ForwardTo = "AuditQueue"}, new SqlFilter("1=1");

This feature comes in very handy for audit/tap scenarios and aggregated message handling.

Sending messages in batch

In service bus, we already had the EnableBatchedOperations to optimize ‘transmission performance’. With this release, we can now send messages in a single batch to a service bus entity. All of that in one transaction. The following code writes a batch of messages to a topic with a filter that accepts all messages with a number different from 8. Since PreFiltering is enabled (see above, no matching subscription), we can easily simulate an exception in the batch, by playing with the loop values. When we make the loop stop before number 8 is hit, all messages are successfully delivered, when we include number 8 (like in the sample), we get the NoMatchingSubscriptionException and not a single message is being delivered.

All of this is achieved by using the SendBatch method of the MessageSender class.

string topicName = "PrefilterBatchTopic";
if (!nsManager.TopicExists(topicName))
{
	nsManager.CreateTopic(new TopicDescription(topicName) { EnableFilteringMessagesBeforePublishing = true });
	var preFilterSubscription = nsManager.CreateSubscription(new SubscriptionDescription(topicName, "NoNumberEight"), new SqlFilter("MessageNumber<>8"));
}

var batchSender = msgFactory.CreateMessageSender(topicName);
// Create list of messages
List<BrokeredMessage> messageBatch = new List<BrokeredMessage>();
for (int i = 0; i < 11; i++)
{
	BrokeredMessage msg = new BrokeredMessage("Test for subscription " + i.ToString());
	msg.Properties.Add("MessageNumber", i);
	messageBatch.Add(msg);
}
batchSender.SendBatch(messageBatch);

Receiving messages in batch

Just like we can send messages in a batch, we can also receive them in a batch. For this, we need to use the ReceiveBatch method of the MessageReceiver class. There are three overloads for this:

msgReceiver.ReceiveBatch(int messageCount);
msgReceiver.ReceiveBatch(IEnumerable<long> sequenceNumbers);
msgReceiver.ReceiveBatch(messageCount, serverWaitTime);

The first overload gets a batch of messages with a maximum of the specified messageCount. If there are 7 messages on the queue and the provided messageCount is 10, the method will return immediately with a batch of all 7 messages. It won’t wait until there are 10 messages on the queue, obviously. The third overload is much the same, except that you can specify a TimeSpan to wait. If no messages arrive during this timespan, an empty Enumerable will be returned.

The second overload is used to get specific messages (for example, messages that have been deferred) from the entity.

The following code reads the messages that have been written in the previous sample.

MessageReceiver msgReceiver = msgFactory.CreateMessageReceiver("PrefilterBatchTopic/Subscriptions/NoNumberEight", ReceiveMode.ReceiveAndDelete);
var messagesReceived = msgReceiver.ReceiveBatch(10, TimeSpan.FromSeconds(3));
Console.WriteLine("Batch received: " + messagesReceived.Count());

Some new properties

The TopicDescription and QueueDescription have some new properties available, aside from the ones discussed above. 

  • Authorization: contains all rules for authorization on the topic or queue. (not on SubscriptionDescription)
  • AccessedAt, CreatedAt, UpdatedAt: these are all DateTime values that indicate the corresponding last actions for a queue. (In my private beta version, the AccessAt was still the DateTime.MinValue, however.)
  • IsAnonymousAccessible: indicates if the queue has opened anonymous access (not on SubscriptionDescription)
  • Status: the status of the queue (Active, Disabled, Restoring)
  • UserMetadata: this is a property that one can use to custom metadata and so to a queue or topic.  

Conclusion

With all recent announcements around symmetry between the cloud and the data center, we can fairly say that Microsoft is the only vendor that is powerful on both levels and gives its customers the choice to run their software in the best way possible.  We truly believe in that vision and that's why we have taken the effort from the beginning of Integration Cloud to make the archticture flexible and modular to support this symmetry.

With Service Bus for Windows Server, we now have the same features available in a server only solution.  And this now also gives me the chance to develop against the service bus while being disconnected. 

Sam Vanhoutte

 

 

 

Updates

  • Removed IIS from the topology diagrams.  While IIS will often be installed and used in combination with Service Bus, it's not a requirement.
 

Posted in: Azure | Service Bus

Tags:


April 12, 2012 at 1:42 PM

This is a post, describing an issue we recently had on the Azure Service Bus. 

 

Situation description

When a single appdomain is opening two (or more) service bus relay endpoints that have the same path (what is added after the servicebus.windows.net), but have a different namespace, the following exception is raised:

System.InvalidOperationException: The ChannelDispatcher at 'sb://repro2.servicebus.windows.net/ordersvc' with contract(s) 'ICustomerService' is unable to open its IChannelListener. ---> System.InvalidOperationException: A registration already exists for URI 'sb://repro2.servicebus.windows.net/ordersvc'.

The following is the configuration of my endpoints (not including the TokenProvider, etc, just the endpoints.

        <endpoint address="http://repro1.servicebus.windows.net/ordersvc"
            binding="basicHttpRelayBinding"
            bindingConfiguration="httpRelayBinding"
            contract="Demo1.Relay.ICustomerService"
            behaviorConfiguration="repro1Behavior" />
        <endpoint address="http://repro2.servicebus.windows.net/ordersvc"
            binding="basicHttpRelayBinding"
            bindingConfiguration="httpRelayBinding"
            contract="Demo1.Relay.ICustomerService"
            behaviorConfiguration="repro2Behavior" />

Why do we need the same services exposed on different namespaces?

Environment seperation

For Codit Integration Cloud, our azure-based integration platform, we are consuming some on-premises web services, exposed over the Azure Service Bus relay binding.  We do this for different services that make part of our runtime.  We also have a deployment cycle where we have different environments (a development, a test, a demo and off course the production environment(s)).

To isolate services, we make sure that every environment has a specific service bus namespace.  This allows for security segregation and to move services on premises, without touching other environments.  So this means that for our EdiFactParser service, we have the following endpoints (different names are being used here):

  • sb://intcloud-dev.servicebus.windows.net/onprem/parse
  • sb://intcloud-test.servicebus.windows.net/onprem/parse
  • sb://intcloud-demo.servicebus.windows.net/onprem/parse
  • sb://intcloud-prod.servicebus.windows.net/onprem/parse

As you can see the only difference in the above mentioned endpoints are the service bus namespaces.  As mentioned, these services are hosted on different servers on premises, but in some cases, we host them together.  (for example: dev & test are sharing the same local server).  In our cases, these services are hosted in BizTalk Server receive locations.

Disaster recovery

In the rare case where an Azure center would be out of the air, all service bus namespaces (hosted in that data center) are unavailable.  (There might be something like service bus federation in the future, but that’s not there yet).  To make sure that our on premises services are still available, we could expose these services on multiple service bus namespaces.  (hosted in different data centers).

In the case of a namespace being unavailable, the client that consumes the service could failover and try to consume the service over the second namespace.

How to work around this

This seems to be a bug in the Service Bus dll implementation, but we didn’t got a confirmation of this by product team yet.  (there might be a good reason for this, allthough I don’t see it).  Anyway, to workaround this, you need to open the different endpoints in separate service hosts.  The following describes how to do this.

In BizTalk Server

We initially had the issue on BizTalk Server, where we expose these services over the service bus.  Both receive locations were hosted in the same BizTalk host.  Just moving both locations to a different BizTalk host, solved the problem. 

In regular .NET applications

If you open the service host yourself, it as easy as creating two instances of the ServiceHost class and have them opening the endpoints seperately.

 

Just wanted to share this one

Sam Vanhoutte