Developing secure mobile apps for Microsoft Dynamics AX 2012



Similar documents
Ektron in the Azure Cloud. Doc. Rev. 1.6 (Mar. 2012)

Configure Microsoft Dynamics AX Connector for Mobile Applications

This module provides an overview of service and cloud technologies using the Microsoft.NET Framework and the Windows Azure cloud.

Workflow approval via

MS 10978A Introduction to Azure for Developers

Course 10978A Introduction to Azure for Developers

Perceptive Connector for Microsoft Dynamics AX

MOC DEVELOPING WINDOWS AZURE AND WEB SERVICES

Setup Guide for AD FS 3.0 on the Apprenda Platform

Attacking WCF Web Services. AppSec DC. The OWASP Foundation. Brian Holyfield Gotham Digital Science

Introduction to Mobile Access Gateway Installation

10978A: Introduction to Azure for Developers

Microsoft MB6-872 Exam Questions & Answers

Introduction to Azure for Developers

Safewhere*ADFS2Logging

Developing Windows Azure and Web Services

Introduction to Building Windows Store Apps with Windows Azure Mobile Services

Microsoft Corporation. Project Server 2010 Installation Guide

OAuth 2.0 Developers Guide. Ping Identity, Inc th Street, Suite 100, Denver, CO

CLAIMS-BASED IDENTITY FOR WINDOWS

Microsoft Dynamics CRM Event Pipeline

Colligo Engage Windows App 7.0. Administrator s Guide

CLOUD COMPUTING & WINDOWS AZURE

ADFS Integration Guidelines

widely available Windows Azure Service Bus 260 pages

Microsoft Introduction to Azure for Developers

AVG Business Secure Sign On Active Directory Quick Start Guide

Contents. Overview 1 SENTINET

Introduction to Directory Services

Single Sign-On Implementation Guide

Developing Microsoft Azure Solutions

Developing Microsoft Azure Solutions 20532A; 5 days

PI Cloud Connect Overview

Bentley CONNECT Dynamic Rights Management Service

GOA365: The Great Office 365 Adventure

Introduction to the Mobile Access Gateway

Tenrox. Single Sign-On (SSO) Setup Guide. January, Tenrox. All rights reserved.

Managing trust relationships with multiple business identity providers (basics) 55091A; 3 Days

Setup Guide Access Manager 3.2 SP3

This chapter describes how to use the Junos Pulse Secure Access Service in a SAML single sign-on deployment. It includes the following sections:

Flexible Identity Federation

Sentinet for Windows Azure SENTINET

The Great Office 365 Adventure

Colligo Briefcase for Windows 6.0. Administrator s Guide

Enabling SSL and Client Certificates on the SAP J2EE Engine

IBM Campaign Version-independent Integration with IBM Engage Version 1 Release 3 April 8, Integration Guide IBM

PingFederate. Windows Live Cloud Identity Connector. User Guide. Version 1.0

New Features in Neuron ESB 2.6

Secret Server Installation Windows 8 / 8.1 and Windows Server 2012 / R2

Cloud Powered Mobile Apps with Azure

Security Best Practices for Microsoft Azure Applications

Hybrid for SharePoint Server Search Reference Architecture

Course 20532B: Developing Microsoft Azure Solutions

Developing Windows Azure and Web Services

Centrify Cloud Connector Deployment Guide

Single Sign-On from Active Directory to a Windows Azure Application

Configuring. Moodle. Chapter 82

AVG Business SSO Connecting to Active Directory

Oracle Service Bus Examples and Tutorials

BlackBerry Enterprise Service 10. Version: Configuration Guide

Installation & Configuration Guide

Enabling Single-Sign-On between IBM Cognos 8 BI and IBM WebSphere Portal

Microsoft Dynamics CRM Server 2011 software requirements

Installing and Configuring vcenter Multi-Hypervisor Manager

ENABLING RPC OVER HTTPS CONNECTIONS TO M-FILES SERVER

PROVIDING SINGLE SIGN-ON TO AMAZON EC2 APPLICATIONS FROM AN ON-PREMISES WINDOWS DOMAIN

Using DSC with Visual Studio Release Management

Sentinet for BizTalk Server SENTINET

SharePoint Comparison of Features

WCF and Windows Activation Service(WAS)

Fusion Installer Instructions

Introduction to the EIS Guide

Microsoft Office 365 Using SAML Integration Guide

Identity Providers. Technical Reference. Interactive Intelligence Customer Interaction Center (CIC) Version Last updated November 5, 2015

Integrating Siebel CRM with Microsoft SharePoint Server

Setup Guide Access Manager Appliance 3.2 SP3

Symplified I: Windows User Identity. Matthew McNew and Lex Hubbard

To install Multifront you need to have familiarity with Internet Information Services (IIS), Microsoft.NET Framework and SQL Server 2008.

Architecture and Data Flow Overview. BlackBerry Enterprise Service Version: Quick Reference

MS 20487A Developing Windows Azure and Web Services

Configuration Guide. BES12 Cloud

IBM WebSphere Adapter for Quick Start Tutorials

Enabling SSO between Cognos 8 and WebSphere Portal

Microsoft Dynamics AX 2012 Installation Guide. Microsoft Corporation Published: April 2011 This content is preliminary and is subject to change.

Enterprise Manager. Version 6.2. Installation Guide

Dynamics CRM with Azure and SharePoint a perfect match. Central and Eastern Europe

CA MDM MOBILE DEVICE MANAGEMENT

Installation Guide for Pulse on Windows Server 2012

Advanced Configuration Administration Guide

Password Reset Server Installation Guide Windows 8 / 8.1 Windows Server 2012 / R2

Using RD Gateway with Azure Multifactor Authentication

Single Sign-On Implementation Guide

Developing Microsoft Azure Solutions 20532B; 5 Days, Instructor-led

The Trusted Technology Partner in Business Innovation PASSION DISCIPLINE INNOVATION TEAMING INTEGRITY

Configuring Single Sign-On from the VMware Identity Manager Service to Office 365

DEPLOYMENT GUIDE Version 2.1. Deploying F5 with Microsoft SharePoint 2010

USING FEDERATED AUTHENTICATION WITH M-FILES

Transcription:

Microsoft Dynamics AX Developing secure mobile apps for Microsoft Dynamics AX 2012 White Paper This document describes how to develop mobile client apps to communicate with Microsoft Dynamics AX from phone or tablet platforms. Authors: Jagruti Pandya and Rob Drollinger, Software Engineers May 2013 http://go.microsoft.com

Table of Contents Introduction... 4 Technical overview... 4 An Application Integration Framework custom service... 5 Active federation for claims-based authentication to the Windows Azure Service Bus by using ACS and ADFS on the client... 6 Outline of the walkthroughs... 6 Design and create the AIF service in Microsoft Dynamics AX 2012... 7 Overview... 7 Development requirements... 7 Create the data contract... 8 Create the data members for the data contract... 8 Create the service class... 9 Create the service operations... 9 Create the service contract...10 Create a privilege to secure the service operation...11 Create a basic inbound integration port...11 Verify that the service has been correctly deployed...12 Establish a listener to the Windows Azure Service Bus... 12 A middle-tier WCF service...13 AIF Windows Azure Service Bus Adapter...14 Comparing the Middle-tier WCF Service and the AIF Windows Service Bus Adapter...14 Create the middle-tier WCF service...15 Prerequisites... 15 Overview... 16 Development requirements... 16 Create the service contract and operation contract... 16 Add a service reference of the AIF service... 18 Call the AIF service operations... 20 Set up the Service Bus relay and deploy the listening endpoint for the middle-tier WCF service.. 22 Validate and extract contents from incoming messages... 27 Build and deploy the middle-tier WCF Windows service... 30 Deploy the AIF service using the AIF Windows Azure Service Bus Adapter....30 Prerequisites... 30 Overview... 31 Authentication Overview... 31 Create Custom Authentication Classes... 31 Registering the authentication component... 33 Encryption Key Containers... 34 Publish AIF Service using the Service Bus Adapter... 35 2

Develop the client to communicate data to the middle-tier WCF service... 38 Development requirements...38 Overview...38 Create a Windows Phone application...38 Add the middle-tier WCF service reference... 38 Lay out and set up the UI controls for required user input... 40 Implement active federation and claims-based authorization for the mobile client... 42 Prerequisites (configuring the trusts)...42 Overview...43 Development requirements...44 Implementation...44 Setup... 44 Get user input... 46 Create and send the request for security token... 48 Create the ACS payload... 52 Additional notes and guidelines... 56 Authenticate the user and send the data to the service... 56 Developing RESTful JavaScript mobile apps for Microsoft Dynamics AX 2012... 60 Design and create the AIF service in Microsoft Dynamics AX 2012...61 Create the middle-tier RESTful service...61 Prerequisites... 62 Development requirements... 62 Create the data contract, service contract, and operation contract... 62 Add a service reference of the AIF service... 65 Call the AIF service operations... 65 Configure the RESTful service bindings and deploy the listening endpoint on Service Bus... 65 Validate and extract contents from incoming JSON messages... 68 Create an HTML5/JavaScript app to communicate data to the WCF middle-tier RESTful service...71 Implement active federation and claims-based authorization for the mobile client by using JavaScript...71 Send the request payload to the REST service...74 Additional resources... 77 3

Introduction This document describes how to create mobile client applications (apps) that enable Microsoft Dynamics AX users to communicate information with Microsoft Dynamics AX 2012. Microsoft offers applications for key mobile scenarios on certain platforms and devices that are compatible with Microsoft Dynamics AX 2012. Microsoft Dynamics customers and partners have a rich ecosystem and powerful story for customizing and extending Microsoft Dynamics AX for the needs of individual organizations and industries. One important goal of this document is to empower our customers and partners to use Microsoft Dynamics AX to create delightful user experiences from any device that works with their customizations. This document provides walkthroughs of a solution that addresses the simple user scenario of an employee capturing information about expenses that the employee incurred while traveling. The document is only meant to teach you the fundamentals of getting devices anywhere in the world talking to Microsoft Dynamics AX. The scenarios you can choose to implement with these lessons are up to your business requirements and your imagination. You can easily envision several exciting scenarios, such as time management, access to customer information while traveling to a customer site, creating sales orders, managing your projects on the road, or just checking up on the factory from across town on your phone or tablet. Technical overview The solution architecture described in this document lets users receive information and send transactions to Microsoft Dynamics AX 2012, even if they are not in the same domain or network as the on-premises instance of Microsoft Dynamics AX. For example, the solution lets clients access a Microsoft Dynamics AX service that is running behind a firewall. The solution has the following requirements: An Application Integration Framework (AIF) service communicates data to and from Microsoft Dynamics AX 2012. Users provide their corporate credentials in the mobile client to interact with Microsoft Dynamics AX 2012 services created for their scenarios. Only authenticated and authorized users can communicate with Microsoft Dynamics AX services by using client applications. 4

The following diagram illustrates how different components interact to enable the mobile app to communicate with Microsoft Dynamics AX. SERVICE BUS Windows Azure HTTP RELAY BINDING SHARED SECRET ACCESS CONTROL SERVICE (ACS) FIREWALL MIDDLE-TIER WCF SERVICE OR IIS 7.5 AIF ROUTING SERVICE MOBILE CLIENT APPLICATION AX 2012 AOS, SQL + AIF service RST: REQUEST FOR SECURITY TOKEN RSTR: REQUEST FOR SECURITY TOKEN RESPONSE Active Directory Federation Services TOKEN SIGNING (ADFS) CERTIFICATE AD DOMAIN CONTROLLER Figure 1 Architectural overview of the entire mobile solution An Application Integration Framework custom service Design an AIF service that can be consumed for the necessary business scenario. To do this, you will need to do the following: Create AIF service and data contracts, and deploy a basic inbound port to expose the service operations for consumption. Implement the service methods in an X++ classes to perform data operations with Microsoft Dynamics AX 2012. The AIF service alone works well for clients who want to consume the service when they are in the same network or domain. However, for mobile scenarios, this would not be useful, because the mobile client will need to communicate with the AIF service hosted on an Application Object Server (AOS) instance that is deployed behind a corporate firewall. Instead of configuring changes in the firewall, such as exposing an Internet Information Services (IIS) server externally to expose the on-premises service, we make use of a secured Service Bus relay. The Microsoft Windows Azure Service Bus and its relayed messaging capability enable applications on other networks to communicate with a system or application that reside on-premises on another network or behind a firewall. 5

We provide two development patterns that leverage the Service Bus s relayed message capability: A custom-built middle-tier WCF service This pattern involves building a middle-tier WCF service that establishes a listener for the Service Bus and routes messages to Microsoft Dynamics AX services according to the routing behavior that the developer chooses. Publishing a service using the AIF Windows Azure Service Bus Adapter This pattern leverages the AIF Windows Azure Service Bus Adapter, which provides a Service Bus listener, hosts the listener in IIS, and routes messages to the AIF service that was deployed using the adapter. You have the flexibility to decide which pattern best fits your application and business requirements. The development patterns are described in Establish a listener to the Windows Azure Service Bus. A table comparing their features is included. Note: The example mobile application described in this document uses the middle-tier WCF service. A service deployed with the AIF Windows Azure Service Bus Adapter can be consumed by following the same guidance. Active federation for claims-based authentication to the Windows Azure Service Bus by using ACS and ADFS on the client The Service Bus s dedicated Access Control Service (ACS) plays a very important role in this solution, controlling the authorization to call a service registered on the Service Bus. It enforces authorization by requiring that the client provide a security token that is issued by a trusted identity provider that authenticates the user. We use active federation to authenticate the user and acquire the user s identity claims. This involves the mobile client actively requesting a security token (containing a set of claims identifying the user) from the corporate Active Directory Federation Services (AD FS) 2.0 by using the WS-Trust protocol. The client will then present this security token containing the claims to the ACS, which will then grant a simple web token (SWT) as a form of authorization for the client to securely send messages via the Service Bus. For the mobile solution, you will need to use an existing corporate AD FS as an identity provider (IdP) to authenticate the user credentials originating from the app. The AD FS will also be used as the security token service (STS) to provide identity claims about the user that will eventually be consumed by the Microsoft Dynamics AX 2012. We will walk you through implementing the described solution in detail. We will also provide sample code and configuration guidance to help you develop mobile applications for Microsoft Dynamics AX 2012 by using services. Outline of the walkthroughs The rest of the document will walk you through the components that you need to implement to create secure mobile applications for Microsoft Dynamics AX 2012. In these walkthroughs, we will be using a simple unreconciled expense capture scenario to illustrate a sample mobile application. In this scenario, an employee of a company that uses the Microsoft Dynamics AX 2012 Time and expense management feature will use the mobile application to capture details of an expense that the employee incurs when on the move. We will use this scenario in all our services, and also in client code samples. You will need to do the following walkthroughs in this document: 1. Design and create the AIF service in Microsoft Dynamics AX 2012 2. Establish a listener to the Windows Azure Service Bus 6

3. Develop the client to communicate data to the middle-tier WCF service 4. Implement active federation and claims-based authorization for the mobile client 5. Authenticate the user and send the data to the service Design and create the AIF service in Microsoft Dynamics AX 2012 Overview As mentioned in earlier, our example illustrates how a Microsoft Dynamics AX user employee can submit expenses from a mobile client when the user is on the move. When the expense makes it into Microsoft Dynamics AX, the expense shows up in the system as an unreconciled expense, which the employee can then add to an expense report. We need to implement an AIF service that accepts this expense data coming from the middle-tier WCF Service, processes it, and then pushes it into the Microsoft Dynamics AX 2012 database. In this walkthrough, we will guide you through the implementation and deployment of the custom AIF service for our mobile example. We will be using some of the existing expense data types and also the existing TrvUnreconciledExpenseTransaction table (which comes with the Travel and expense module in Microsoft Dynamics AX 2012). We will create a service contract for the AIF service that will be exposed to the clients consuming this service. In our expense capture example, the middle-tier WCF service will consume the AIF service that we create (named UnreconciledExpenseService). For more guidance about creating custom AIF services, see Walkthrough: Exposing an X++ Class as a Data Contract [AX 2012]. Note: The following example uses a standard implementation of custom AIF service functionality. If you are already familiar with this, you can skip this section. Note: Although this example walks you through exposing a custom AIF service, you can apply the same principles to utilize Microsoft Dynamics AX document services or system services, such as the query service. The following points summarize the walkthrough article mentioned earlier: 1. Create the data contract. This is the data object that is passed into the service call. 2. Create the data members that will be exposed as part of the data contract. 3. Define the service class. 4. Implement the service operations offered by the service contract. 5. Add the service class to the Application Object Tree (AOT). 6. Create a basic inbound port for the service to deploy the service. 7. Activate the port to make it consumable by external clients. Development requirements To complete this walkthrough, you will need the following: Microsoft Dynamics AX 2012 installed and configured, together with the Active Directory server A development license for Microsoft Dynamics AX 2012 7

For our sample code, which covers an expense capture scenario: The Travel and expense management module in Microsoft Dynamics AX 2012 The Human resources module in Microsoft Dynamics AX 2012 Microsoft Dynamics AX users added and mapped to workers, with the Employee role Create the data contract 1. In the Developer Workspace, create a class in the AOT named UnreconciledExpenseRecord. Set the RunOn property to Called from. 2. In the class declaration, define the data members. For our expense capture scenario, we want the user to send the expense amount, currency, expense date, and some notes. 3. Apply the DataContractAttribute attribute to the class. X++ [DataContractAttribute] public class UnreconciledExpenseRecord TransDate TrvFreeText AmountCur CurrencyCode transactiondate; notes; transactioncurrencyamount; transactioncurrencycode; Create the data members for the data contract Add new methods in the class, and apply the DataMemberAttribute attribute to these methods. X++ [DataMemberAttribute] public TrvFreeText parmnotes(trvfreetext _notes = notes) notes = _notes; return notes; [DataMemberAttribute] public AmountCur parmtransactioncurrencyamount( AmountCur _transactioncurrencyamount = transactioncurrencyamount) transactioncurrencyamount = _transactioncurrencyamount; return transactioncurrencyamount; [DataMemberAttribute] public CurrencyCode parmtransactioncurrencycode( CurrencyCode _transactioncurrencycode = transactioncurrencycode) transactioncurrencycode = _transactioncurrencycode; return transactioncurrencycode; 8

X++ [DataMemberAttribute] public TransDate parmtransactiondate(transdate _transactiondate = transactiondate) transactiondate = _transactiondate; return transactiondate; Create the service class Create a class in the AOT named UnreconciledExpenseService, and set the RunOn property to Server. The class declaration is as follows. X++ /// <summary> /// The <c>trvunreconciledexpenseservice</c> is the unreconciled /// expense transaction Web service class. /// </summary> public class UnreconciledExpenseService // These macros are used to specify the SubCode on AifFaults. // Their values will not be translated allowing the consumer // of the service to identify the cause // of the fault and take appropriate action. #DEFINE.ParameterValidationError('ParameterValidationError') #DEFINE.UnreconciledExpenseCreationFailed('UnreconciledExpenseCreationFailed') Create the service operations In the UnreconciledExpenseService class, create a public method named createrecord, which will take a reference of an unreconciled expense transaction that the user submitted and insert the data into the TrvUnreconciledExpenseTransaction table. X++ [SysEntryPointAttribute(true)] public recid createrecord(unreconciledexpenserecord _unreconciledexpenserecord) TrvUnreconciledExpenseTransaction recid recid createdrecid; workerid; unreconciledexpensetrans; if (!_unreconciledexpenserecord) // An instance of data contract class is required throw error(error::wronguseoffunction(funcname())); 9

X++ workerid = DirPersonUser::findUserWorkerReference(curUserId()); //Validates if user is related to a worker in AX if (workerid == 0) throw AifFault::faultList("@SYS335749", #ParameterValidationError); ttsbegin; unreconciledexpensetrans.transdate = _unreconciledexpenserecord.parmtransactiondate(); unreconciledexpensetrans.worker = workerid; unreconciledexpensetrans.notes = _unreconciledexpenserecord.parmnotes(); unreconciledexpensetrans.transactioncurrencyamount = _unreconciledexpenserecord.parmtransactioncurrencyamount(); unreconciledexpensetrans.transactioncurrencycode = _unreconciledexpenserecord.parmtransactioncurrencycode(); if (unreconciledexpensetrans.validatewrite()) unreconciledexpensetrans.insert(); ttscommit; createdrecid = unreconciledexpensetrans.recid; if (!createdrecid) //Creation of record failed throw AifFault::faultList("@SYS335750, #UnreconciledExpenseCreationFailed); return createdrecid; As you can see in the preceding code, we are fetching the worker who is associated with the expense based on a current user ID. As you will see in the Create the middle-tier WCF service section, the call to the service operation is made under the context of the mobile Microsoft Dynamics AX user submitting the request by setting the CallContext property. Therefore, the curuserid value will be the Microsoft Dynamics AX user ID of the original user submitting the request. Create the service contract To create the service contract that is made available to clients consuming the service, create a new service in the Services node of the AOT that implements the service class we created (UnreconciledExpenseService). You must also add the operation exposed by the class (createrecord). For guidance, see Walkthrough: Exposing an X++ Class as a Data Contract [AX 2012]. 10

Create a privilege to secure the service operation At this point, we want to create a special privilege to help provide secure access when the createrecord method is called. We require that this privilege be added to the Employee role (AOT name: HCMEmployee), so that only those users who have this privilege call the createrecord service method. Create a privilege and add the operation to the Entry Points object of the Privilege. 1. In the Development workspace go to AOT > Security > Privileges > Right click and New Privilege. 2. Add a privilege and name it UnreconciledExpenseServiceCreate. 3. Go to the Entry Point node and right click and add a New Entry point and set: Property Name ObjectType ObjectName ObjectChildName AccessLevel Value UnreconciledExpenseServiceCreate ServiceOperation UnreconciledExpenseService createrecord Invoke 4. You can now add this Privilege to the Duty TrvTravelAndExpenseServiceOperations. (AOT> Security>Duties>New Privilege) Note: This duty is already incorporated in the HCMEmployee role s list of duties. Note: If you have Dynamics AX 2012 R2 installed, you will also need to add two more privileges (LogisticsAddressCountryRegionView and LogisticsPostalAddressView) to the TrvTravelAndExpenseServiceOperations duty for the above implemented createrecord operation to work correctly. Create a basic inbound integration port The following instructions pertain to the middle-tier WCF service only. When using the AIF Windows Azure Service Bus Adapter, do not create a basic inbound integration port. Instead, go to Deploy the AIF service using the AIF Windows Azure Service Bus Adapter. In order to deploy the service we must create a basic inbound integration port. First, we need to register the service in the AOT: Go to the Service that we created in the step above: \Services\UnreconciledExpenseService. 11

Right-click > Add-Ins > Register service. The AIF services window will open. Verify if the service that you created is in the list of AIF services. Close the form. Next, we need to activate the port in order to make it available to external clients: Click System Administration > Setup > Services and Application Integration Framework > Inbound ports. Click New to create a new inbound port for this service. Specify a Port name for example: UnreconciledExpense Click on Service operations to add a required service operation. In our example, add operation UnreconciledExpenseService.createRecord from the list of remaining service operations and then close. Click Activate to activate the port. Verify that the service has been correctly deployed 1. In the Inbound ports form, copy the WSDL URI. 2. Open the WSDL URI in a browser to view the WSDL file. To consume the service, clients need to add the WSDL URI address as the service reference to generate the service proxy. Establish a listener to the Windows Azure Service Bus Both the AIF service that is published using the Service Bus adapter and a middle-tier WCF service will establish a listener to the Windows Azure Service Bus. This listener is an out-bound connection to the Service Bus on which incoming messages from clients are relayed. A message relayed in this manner is then routed to Microsoft Dynamics AX by a routing service hosted in IIS 7.5 (if using the Service Bus adapter) or by the routing service in the middle-tier WCF service. 12

A middle-tier WCF service Creating a WCF service that deploys its listening endpoint on a Windows Azure Service Bus namespace involves the following tasks: Define a service contract that is in line with the requirements of the AIF service contract (that is, clients pass data that is required by the AIF service per the business scenario). Define a URI that is used to listen on the Service Bus for example, https://<azurenamespace>.servicebus.windows.net/expense/. Set up a secure channel (HTTP relay binding) with the Service Bus. Extract information from the incoming message sent by the client. (The client application creates its request by using the service proxy generated from the WCF service, and sends the request to this endpoint URI. The Service Bus will relay the message to the middle-tier WCF service). The WCF service then calls the AIF service and passes all the data the AIF service needs. It is very important that only authorized users be allowed to send and receive messages through the Service Bus. In addition, we require that only authorized users be able to make calls to the WCF service. These users exist in an enterprise s Active Directory Domain Services and can be authenticated by a deployed Active Directory Federation Service (AD FS). Furthermore, we need to call the AIF service in the context of the authorized user, and therefore need information about the user in the data that is passed from the client to the WCF service. 13

AIF Windows Azure Service Bus Adapter The AIF Windows Azure Service Bus Adapter extends the existing AIF functionality and uses IIS 7.5 to provide a method to deploy services by using cloud computing. The following infrastructure helps accomplish this: IIS 7.5 The Service Bus adapter leverages IIS to host Microsoft Dynamics AX services published with an HTTP adapter, or by using the new Service Bus adapter. IIS hosts the Service Bus listener and a routing service (both of which are WCF services) that work in tandem to pass messages from the Service Bus to Microsoft Dynamics AX. Authentication Classes Each call to Microsoft Dynamics AX services through the Service Bus must be authenticated. With the Service Bus adapter hotfix, the AIF now allows registering authentication classes to authenticate inbound Service Bus messages and extract the user s Microsoft Dynamics AX credentials. Registering authentication classes is a one-time configuration step, and the authentication classes can be used across multiple Service Bus namespaces and published services after they are registered. AIF Service Bus Namespace Registration Registering a Service Bus namespace is a one-time step for each namespace you wish to use. Registration includes supplying the namespace name, access key credentials, authentication classes, and X.506 signing certificate that is used to sign the ADFS SAML token. The AIF uses all of these in order to establish trust with the Service Bus before opening a connection. AIF Windows Azure Service Bus Adapter After you have registered a Service Bus namespace with AIF, you can begin publishing Microsoft Dynamics AX services by using the AIF Windows Azure Service Bus Adapter. The process of publishing Microsoft Dynamics AX AIF services has not changed. Create a new port (using the form AifInboundPorts form), select the AIF Windows Azure Service Bus Adapter, and then select the service operations to expose on the port. After you activate the port, your service will be accessible from the cloud. For more information about adapters, see http://msdn.microsoft.com/en-us/library/gg751348.aspx. All of these items are described in detail in Deploy the AIF service to the Azure Service Bus. Comparing the Middle-tier WCF Service and the AIF Windows Service Bus Adapter Use the following table to compare the capabilities and requirements of the Middle-tier WCF service and the AIF Windows Azure Service Bus Adapter. Both options provide solutions for mobile application development, but they differ in implementation, infrastructure, and technical capabilities. The following table highlights the differences. Configuration and Setup Middle-tier WCF Service Requires developing the Middle-tier WCF service. AIF Windows Azure Service Bus Adapter Can be configured by an administrator. Configuring custom authentication may require a developer. Failover Support IIS Does not require IIS Requires IIS 7.5 to host the Service Bus listener. Failover is handled by installing multiple middle-tier WCF services on separate machines. Failover is handled through available IIS failover strategies. 14

Multiplicity Routing to multiple AX instances REST support Protocol support Logging and eventing Authentication Can listen to multiple Service Bus namespaces simultaneously from one middle-tier WCF service instance. Each middle-tier WCF service can serve multiple AX instances. The WCF service developer creates this routing behavior. Can be configured to expose a RESTful endpoint, or any other service contract type and binding that is possible in WCF as a façade for the backing AIF service. Endpoints hosted on Service Bus can support any transport (such as HTTP andnet.tcp) or messaging (such as SOAP and JSON) protocols available for a WCF service, including custom message encoders or other service behaviors (enabling compression or other message manipulation or inspection, for example). As part of configuring the Middle-tier WCF service, a developer must write a logging service. Endpoints can be either authenticated or unauthenticated (to allow client bootstrapping traffic, for example). Each Service Bus namespace must be registered with exactly one IIS website. An IIS instance can host multiple websites. Each IIS website can serve a different Microsoft Dynamics AX instance. Each website is tied to exactly one Service Bus namespace within a Microsoft Dynamics AX instance. We recommend that you do not share a website across Microsoft Dynamics AX instances. Not currently supported. The SOAP service contract exposed to the client on Service Bus is always identical to the service contract as defined in Microsoft Dynamics AX. Supports only HTTPS for service calls. Logs connection status in IIS event log. Endpoints must always be authenticated, so it is the client s responsibility to know which identity provider to authenticate against. Choosing between the two approaches is primarily a matter of balancing customizability with development costs. The middle-tier WCF service has higher development costs because it requires you to manually create and install a WCF service that listens to the Service Bus and routes service calls to Microsoft Dynamics AX. However, with the middle-tier WCF service you can use the messaging protocols of your choice, expose different contracts to your clients, provide custom message routing behavior, and serve multiple installations of Microsoft Dynamics AX or other back-end systems. The Service Bus adapter has a lower development cost because automatically creates a WCF service and hosts it in IIS. By using the Service Bus adapter, your only development costs are in configuration: providing Service Bus information (namespace, access key), AD FS information (certificate thumbprint), and registering authentication classes. However using the Service Bus adapter does not allow customization of the WCF service that is hosted in IIS. The WCF service hosted in IIS can perform only the action of authenticating and routing service calls. The routing behavior only supports routing relayed messages to the installation of Microsoft Dynamics AX that the service was published from. Next, we will walk through the steps that are necessary to build the middle-tier WCF service, followed by the steps that are necessary to publish a service using the AIF Windows Azure Service Bus Adapter. Create the middle-tier WCF service Prerequisites An X.509 token signing certificate is installed on the AD FS 2.0 server and on the machine running the WCF service, in the Trusted Root Certification Authorities store. For guidance, see Microsoft Dynamics AX Connector for Mobile Applications. You have the thumbprint from that certificate. 15

A Windows Azure Service Bus namespace has been created, and the shared secret and issuer name for the namespace are available. For guidance, see Microsoft Dynamics AX Connector for Mobile Applications. The machine that the middle-tier WCF service runs on should be in the same domain or on the same network as the Microsoft Dynamics AX 2012 AOS machine (which can be the same machine or a different one). Overview The following steps are required to create the WCF SOAP-based service that will receive service requests from the mobile client, relayed by the Service Bus. For the following example, we will create the WCF service as a Windows service. Development requirements Microsoft Visual Studio 2010 and the Microsoft.NET Framework version 4. The Service Bus component (Microsoft.ServiceBus.dll), which is included with the Windows Azure Libraries for.net. To install it, visit the Windows Azure SDK download page. The Windows Identity Foundation runtime, which can be downloaded from Windows Identity Foundation (WIF) SDK. Download the 4.0 version for Visual Studio 2010 and the.net Framework version 4.0. For more information about the WIF SDK, see Windows Identity Foundation SDK. Create the service contract and operation contract 1. Open Visual Studio, and create a new Windows Service.NET Framework version 4 project named ExpenseConnectorService. 16

2. Rename the Service1.cs class ConnectorService.cs. This class contains the OnStart and OnStop methods for the Windows service, which we will use to open a listening endpoint. using System.ServiceModel; using System.ServiceProcess; namespace ExpenseConnectorService public partial class ConnectorService : ServiceBase private ServiceHost host; public ConnectorService() InitializeComponent(); protected override void OnStart(string[] args) // Deploy the endpoint protected override void OnStop() // Close the endpoint connection 3. Add the System.ServiceModel reference to the project, and include the System.ServiceModel namespace in all the following classes. 4. Add a new interface for the service contract, named IExpenseService, to the project, and create the service contract and operation contract as shown here. [ServiceContract(Name = "ExpenseServiceContract", Namespace = "http://samples.microsoft.com/dynamicsax/")] public interface IExpenseServiceContract [OperationContract] long CreateExpense(DateTime datetime, decimal amount, string currency, string comments); 17

5. Create another class for the service operation implementation. Per the contract we created, create a class named ExpenseService, which implements the IExpenseServiceContract interface. [ServiceBehavior(Name = "ExpenseService")] public class ExpenseService : IExpenseServiceContract public long CreateExpense(DateTime datetime, decimal amount, string currency, string comments) // Implementation Any client consuming this service will make a call to the service s CreateExpense operation and will be required to pass information as stated in the method parameters. Later, we will add code to this method that will process the incoming SOAP message in the following way: Extract the Security Assertion Markup Language (SAML) token from the header of the message. The token is issued by the identity provider (the corporation s Active Directory Federation Service). Perform token validation. Extract the claim assertion that was requested (the windowsaccountname claim). Use the expense data embedded in the SOAP message body, and make a call to the AIF service operation. All the processing, validating, and extracting of claims from the token is facilitated by the Windows Identity Foundation libraries. Add a service reference of the AIF service We need to generate a client proxy of the AIF service to gather the service contract, bindings, and address for the AIF endpoint. To add the service reference, we use the WSDL exposed by the inbound port that was activated in the Design and create the AIF service in Microsoft Dynamics AX 2012 section. 18

1. Go to Solution Explorer, right-click References, and then select Add service reference. In the Add Service Reference form, enter the WSDL address http://aosmachine:8101/dynamicsax/services/unreconciledexpense. You will see the createrecord operation exposed by the service. Edit the namespace, naming it AXExpenseServiceReference, and then click OK to add the reference to the project. The reference shows up in the Service References node in Solution Explorer. Also observe that the client proxy file named Reference.cs is generated within the project in a folder (\Service References). 2. Observe that several changes have automatically been made to the app.config file in the project with regard to the bindings, security protocols, and so on, and also the URI of the endpoint deployed to enable the middle-tier service to communicate with the AIF endpoint on Microsoft Dynamics AX. Verify that the following configuration values are created in the app.config file. 19

NetTcpBinding specification for connecting to the AIF endpoint exposed on the AOS server APP.CONFIG <system.servicemodel> <bindings> <nettcpbinding> <binding name="nettcpbinding_unreconciledexpenseservice" closetimeout="00:01:00" opentimeout="00:01:00" receivetimeout="00:10:00" sendtimeout="00:01:00" transactionflow="false" transfermode="buffered" transactionprotocol="oletransactions" hostnamecomparisonmode="strongwildcard" listenbacklog="10" maxbufferpoolsize="524288" maxbuffersize="65536" maxconnections="10" maxreceivedmessagesize="65536"> <readerquotas maxdepth="32" maxstringcontentlength="8192" maxarraylength="16384" maxbytesperread="4096" maxnametablecharcount="16384"/> <reliablesession ordered="true" inactivitytimeout="00:10:00" enabled="false"/> <security mode="transport"> <transport clientcredentialtype="windows" protectionlevel="encryptandsign"/> <message clientcredentialtype="windows"/> </security> </binding> </nettcpbinding> </bindings> </system.servicemodel> Definition of the endpoint address, binding configuration, and contract of the AIF service APP.CONFIG <client> <!-- This address should be set to the URI of the endpoint deployed on AX. It should be of the form: "net.tcp://<aos_machine_name>:8201/dynamicsax/services/<inbound_port_name>" --> <endpoint address="net.tcp://aosmachine:8201/dynamicsax/services/unreconciledexpense" binding="nettcpbinding" bindingconfiguration="nettcpbinding_unreconciledexpenseservice" contract="axexpenseservicereference.unreconciledexpenseservice" name="nettcpbinding_unreconciledexpenseservice"> </endpoint> </client> As shown in the <client> element, the endpoint address can be configured to point to a machine that hosts the AOS machine on which the AIF service is deployed and activated. In this way, the middle-tier service can be run on any machine, provided that it is on the same network as the AOS machine, to make the service call by using the NetTcp binding. Call the AIF service operations After you have added the service reference, the next step is to use its operation contract and make the necessary method call. 20

1. Include the AIF service namespace ExpenseConnectorService.AXExpenseServiceReference in the ExpenseService class. using ExpenseConnectorService.AXExpenseServiceReference; 2. Create a new private method named SubmitExpenseToAX, which will do the following: 1. Populate the values of the UnreconciledExpenseRecord data member of the UnreconciledExpenseService AIF service 2. Call UnreconciledExpenseService s createrecord operation 3. Return the result (the RecID value returned by the AIF service operation) Later, we will call this method in the exposed service operation (CreateExpense). private long SubmitExpenseToAX(DateTime datetime, decimal amount, string currency, string comments, string windowsaccountname) UnreconciledExpenseRecord record = new UnreconciledExpenseRecord() ; parmnotes = comments, parmtransactioncurrencyamount = amount, parmtransactiondate = datetime, parmtransactioncurrencycode = currency using (UnreconciledExpenseServiceClient client = new AXExpenseServiceReference.UnreconciledExpenseServiceClient()) UnreconciledExpenseRecord expenserecord = record; CallContext callcontext = new CallContext() LogonAsUser = windowsaccountname ; return client.createrecord(callcontext, expenserecord); The preceding method creates an instance of the service s client, sets the data member values, and then makes the final call to the createrecord operation. Also notice the CallContext object that is passed into the service call. In Microsoft Dynamics AX, values such as the user, company, and so on can be used when the service call is executed and are sent in the message header from the service client by using the CallContext object. In our example, we want to pass the mobile user s information when making the createrecord call, so that the unreconciled expense is created in the context of the user. LogonAsUser has been set to windowsaccountname. This is the value of the claim that was requested from the AD FS (in the form domain\useralias) and identifies the user who submitted the request from the client. Remember that this user must exist in the Microsoft Dynamics AX system, and because Microsoft Dynamics AX uses the same Active Directory service as the identity provider, it will recognize and then be able to authorize this user. 21

Set up the Service Bus relay and deploy the listening endpoint for the middle-tier WCF service To configure the middle-tier service s endpoint to listen on the Service Bus, we need to update the app.config file as follows: Add a BasicHttpRelayBinding binding for communicating with the Service Bus. Provide the service contract name and the service endpoint address. Set up the required binding configuration by specifying Service Bus credentials. 1. Define the BasicHttpRelayBinding configuration by adding the following under the <bindings> element in the <system.servicemodel> section. APP.CONFIG <basichttprelaybinding> <binding name="basichttprelaybinding_servicebus"> <security mode="transport" relayclientauthenticationtype="relayaccesstoken"/> </binding> </basichttprelaybinding> The preceding configuration sets the binding to have end-to-end transport security. We also set the value of the relayclientauthenticationtype parameter to RelayAccessToken, which forces clients of the service to authenticate to the Service Bus before sending across any messages. As shown in Figure 1, to connect to the Service Bus, the client presents the Service Bus with the security token (SWT) issued by the ACS. 22

2. Define configuration values for the endpoint behavior. APP.CONFIG <behaviors> <endpointbehaviors> <behavior name="sharedsecretclientcredentials"> <transportclientendpointbehavior credentialtype="sharedsecret"> <clientcredentials> <!-- The issuername & issuersecret here should be set to the values for the service account on Service Bus you wish to use to listen. By default, the namespace will come with an admin user (issuername) of "owner" with a 256-bit secret key (issuersecret) available in the Windows Azure management portal.--> <sharedsecret issuername="owner" issuersecret="xxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxx="/> </clientcredentials> </transportclientendpointbehavior> </behavior> </endpointbehaviors> </behaviors> As shown in the preceding configuration, transportclientendpointbehavior is used to specify the Service Bus credentials for the endpoint that will be deployed on the Service Bus. The shared secret values of issuername and issuersecret are values of Default Issuer and Default Key of your namespace that was set up in Windows Azure Management Portal. Note: If you want to collect the necessary information from the user at run time via a UI, System.ServiceModel and Microsoft.ServiceBus provide APIs to set all these configuration values programmatically. 3. Deploy the listening endpoint. To specify the service contract for the middle-tier service, the binding, and the behavior configuration (all of which were defined in the preceding points), add the following code snippet in the app.config file, under the <services> element. APP.CONFIG <services> <service name="expenseconnectorservice.expenseservice"> <endpoint address="" behaviorconfiguration="sharedsecretclientcredentials" binding="basichttprelaybinding" contract="expenseconnectorservice.iexpenseservicecontract"/> <host> <baseaddresses> <!-- This baseaddress should be set to the URI you intend to listen to on the Service Bus. It should be of the form: "https://<appfabric_namespace>.servicebus.windows.net/expense/" --> <add baseaddress="https://contosomobile.servicebus.windows.net/expense/"/> </baseaddresses> </host> </service> </services> 23

4. Deploy the metadata endpoint for the service. To generate a client proxy for our mobile client, we will need to expose a metadata endpoint address. Under the <behaviors>/<servicebehaviors> node, add the following. Make sure that you enable the servicemetadata node. APP.CONFIG <servicebehaviors> <behavior name="servicemetadata"> <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> <servicedebug includeexceptiondetailinfaults="false"/> <!--Enable this element when publishing metadata--> <servicemetadata /> </behavior> </servicebehaviors> We now need to update the <services> section that we used to specify the service contract, binding, and behavior configurations. Set behaviorconfiguration to servicemetadata, and then add a local MEX endpoint. APP.CONFIG <services> <service name="expenseconnectorservice.expenseservice" behaviorconfiguration="servicemetadata"> <endpoint address="" behaviorconfiguration="sharedsecretclientcredentials" binding="basichttprelaybinding" contract="expenseconnectorservice.iexpenseservicecontract"/> <endpoint contract="imetadataexchange" binding="mexhttpbinding" address="http://localhost/mex" /> Bus <host> <baseaddresses> <!-- This baseaddress should be set to the URI you intend to listen on the Service It should be of the form: "https://<appfabric_namespace>.servicebus.windows.net/expense/" --> <add baseaddress="https://contosomobile.servicebus.windows.net/expense/"/> </baseaddresses> </host> </service> </services> The client proxy that consumes this service can then be generated by using the http://<middletierservicemachinename>/mex metadata URI. 24

5. We also need to update the app.config file to register the preceding Service Bus behavior and binding extensions. APP.CONFIG <extensions> <behaviorextensions> <add name="transportclientendpointbehavior" type="microsoft.servicebus.configuration.transportclientendpointbehaviorelement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </behaviorextensions> <bindingextensions> <add name="basichttprelaybinding" type="microsoft.servicebus.configuration.basichttprelaybindingcollectionelement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </bindingextensions> </extensions> 6. Finally, open the Service Bus connection, and start listening on the endpoint. Note: The on-premises service connects to the relay service over ports 9350 9354; however, if these are unavailable, the service will try to call back to port 80 (HTTP) or 443 (HTTPS). Add the following code snippets to the OnStart method in the ConnectorService class. protected override void OnStart(string[] args) // Note that all binding, endpoint, service, behavior configuration // for this ServiceHost is located in the app.config host = new ServiceHost(typeof(ExpenseConnectorService.ExpenseService)); WriteToEventViewer("Opening the Service endpoint connection " + host.baseaddresses[0].tostring()); try host.open(); WriteToEventViewer(string.Format("Listening on: 0", host.description.endpoints.find( typeof(expenseconnectorservice.iexpenseservice)).address)); catch (Exception e) WriteToEventViewer(e.Message); 25

private void WriteToEventViewer(string eventmessage) string source = "Expense WCF Service"; if (!EventLog.SourceExists(source)) EventLog.CreateEventSource(source, "Application"); EventLog.WriteEntry(source, eventmessage, EventLogEntryType.Information); protected override void OnStop() host.close(); You can also close the connection in the OnStop method. There are several events you may want to hook into and log, so that you can monitor the status of the relay binding and other such events. You can log events in the event viewer by using System.Diagnostics. 26

Validate and extract contents from incoming messages The next step is to inspect the message coming from the client. The incoming SAML message contains a header that holds the windowsaccountname claim in the security token. This claim is issued by the AD FS 2.0. For more information about requesting claims, see the Implement active federation and claims-based authorization for the mobile client section. Windows Identity Foundation is used to validate the security token and the issuer, after which we extract the claim that we need to make the AIF service call. 27

1. Update the app.config file, adding configuration values for handling the SAML security token issued by the AD FS. APP.CONFIG <microsoft.identitymodel> <service> <securitytokenhandlers> <securitytokenhandlerconfiguration> <audienceuris mode="never"/> <issuernameregistry type="microsoft.identitymodel.tokens.configurationbasedissuernameregistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <trustedissuers> <!-- The STS that issues the SAML token exchanged at ACS must be added as a trusted issuer here. The thumbprint & name values should be obtainable from the public signing certificate exposed on the STS' federation metadata --> <add thumbprint="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" name=""/> </trustedissuers> </issuernameregistry> </securitytokenhandlerconfiguration> </securitytokenhandlers> </service> </microsoft.identitymodel> APP.CONFIG <configsections> <section name="microsoft.identitymodel" type="microsoft.identitymodel.configuration.microsoftidentitymodelsection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </configsections> The issuer (also known as the identity provider in our case, the corporate AD FS) uses a token signing certificate to digitally sign the SAML token. Therefore, the thumbprint of the token signing certificate must be specified in the service s configuration as shown in the first code snippet, in the <trustedissuers> section. This will be used to validate the digital signature when the token is validated. 2. Add Microsoft.IdentityModel and System.IdentityModel references to the project, and add the following namespaces to the ExpenseService.cs file. using System.IdentityModel.Tokens; using Microsoft.IdentityModel.Claims; using Microsoft.IdentityModel.Configuration; 3. Add an implementation to the CreateExpense service operation to do the following: 1. Extract the security token from the custom SOAP header PassthroughBinarySecurityToken. This header information is passed by the mobile client calling the service. 28

2. Inspect the SAML token. 3. Use WIF to validate the token by using the thumbprint and other configuration values from the service configuration. 4. Extract the required claim (windowsaccountname) from the token. 5. Make the call to the SubmitExpenseToAX method, which will make the AIF service call. public long CreateExpense(DateTime datetime, decimal amount, string currency, string comments) string samltokenheader = (string)operationcontext.current.incomingmessageheaders[operationcontext.current.incoming MessageHeaders.FindHeader("PassthroughBinarySecurityToken", "")].ToString(); string encodedsamltoken = samltokenheader.split('<', '>')[2]; byte[] bintoken = Convert.FromBase64String(encodedSamlToken); string samltoken = new string(encoding.utf8.getchars(bintoken)); // Load the app.config settings where we specify the audience & issuer that we'll // accept in a token var config = new ServiceConfiguration(); var handler = config.securitytokenhandlers[ Microsoft.IdentityModel.Tokens.SecurityTokenTypes.Saml11TokenProfile11]; ClaimsIdentityCollection claimsidentity = null; // Convert the raw token into something that can be inspected using (XmlReader reader = XmlReader.Create(new StringReader(samlTokenString))) SecurityToken token = handler.readtoken(reader); // This is the primary WIF call that // 1) Performs all the token validation // a. Format, token type, key type, version, etc. // b. Expiration // c. Audience/AppliesTo/Relying party // d. Issuer // e. Signature // 2) generates a ClaimsIdentityCollection that contains what the app actually // cares about claimsidentity = handler.validatetoken(token); IPrincipal principal = new ClaimsPrincipal(claimsIdentity); IClaimsIdentity identity = (IClaimsIdentity)principal.Identity; windowsaccountname = identity.claims.single(claim => claim.claimtype == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname").value; 29

return SubmitExpenseToAX(expenseData, windowsaccountname); Build and deploy the middle-tier WCF Windows service 1. Build the entire project. 2. Add the ProjectInstaller.cs file, and create an installer (Setup project) for the Windows service by following the guidance at Walkthrough: Creating a Windows Service Application in the Component Designer. 3. Make sure that you add the primary output from the ExpenseConnectorService project to the installer and all its dependencies (Microsoft.ServiceBus.dll, Microsoft.IdentityModel.dll, and the.net Framework dependencies). The user account that the service is deployed and run should be the.net Business Connector proxy account. By using a proxy, you guarantee that.net Business Connector can connect on behalf of Microsoft Dynamics AX users when it authenticates with an AOS instance. For more information about how to create and set up the.net Business Connector proxy account, see Specify the.net Business Connector proxy account [AX 2012]. Also, note the following requirements for the.net Business Connector proxy account: It must be a Windows domain account. It must be a dedicated account (used only by.net Business Connector). It must have a password that does not expire. It must not have interactive logon rights. It must not be a Microsoft Dynamics AX user. In addition, it is important that the.net Business Connector proxy user account be added as an Administrator on the machine running the service (so that it has access to the ports required to deploy listening endpoints on the Service Bus). 4. Run the installer, and provide the.net Business Connector proxy user s user name and password, which will run the WCF Windows service. Deploy the AIF service using the AIF Windows Azure Service Bus Adapter Prerequisites The Service Bus component (Microsoft.ServiceBus.dll v1.8), which is included with the Windows Azure Libraries for.net. To install it, visit the Windows Azure SDK download page. (The Microsoft.ServiceBus.dll must be placed in the Bin folder of the website that the service is deployed to) You have installed the AIF Windows Azure Service Bus Adapter Hotfix: http://support.microsoft.com/kb/2845539 You have installed the AX Web Services on IIS 7.5. An X.509 token signing certificate is installed on the AD FS 2.0 server and on the machine that is running the WCF service, in the Trusted Root Certification Authorities store. For more information, see Microsoft Dynamics AX Connector for Mobile Applications. You have the thumbprint from that certificate. 30

A Windows Azure Service Bus namespace has been created, and the shared secret and issuer name for the namespace are available. For more information, see Microsoft Dynamics AX Connector for Mobile Applications. Overview The following steps enable publishing an AIF service that listens to messages incoming from the Azure Service Bus, without a middle-tier WCF service. You must register your Windows Azure Service Bus namespace with the AIF before you can publish services to the Service Bus. Registration requires that you supply the X++ and WCF authentication classes that will authenticate incoming Service Bus messages. Go to Create the authentication classes, and then go to Register your Service Bus namespace with the AIF. Next, see Publish your AIF service. Authentication overview The Service Bus requires each on-premises service to be authenticated and authorized to listen on a particular address before establishing a new relay connection. Clients must also be authenticated and authorized before the Service Bus will relay messages on their behalf. The Service Bus relies on ACS for authenticating services and clients. Service authentication Microsoft Dynamics AX services use a shared secret token provider to authenticate with the Service Bus. The shared secret is provided to the AIF when you Register your Service Bus Namespace. Client authentication The following two types of client authentication are required: Service Bus authentication Clients are required to provide a send claim in order to be able to send messages to a service on the Service Bus. The ACS must trust the identity provider used by the client. This must be set up as described in Microsoft Dynamics AX Connector for Mobile Applications. Microsoft Dynamics AX authentication When the Service Bus relays a message to the on-premises service, the caller identity is used to log on to Microsoft Dynamics AX. This caller identity is determined by calling a custom authentication component to parse the incoming message token and to provide a valid claims identity. The user specified by the claims identity must be a valid Microsoft Dynamics AX user. Sample authentication component A sample ADFS authentication component is provided here: http://blogs.msdn.com/b/aif/archive/2013/04/29/aif-windows-azure-service-bus-adapter.aspx. You can use it as it is or modify it to suit your needs. This component searches for an ADFS token in a custom message header titled PassthroughBinarySecurityToken. If this token is found, the token is validated by using the trusted issuer thumbprint of the ADFS STS and the claims that are extracted. A Windows Account Name claim type identifies the user account. For more information, see http://blogs.msdn.com/b/willpe/archive/2010/10/25/windows-authentication-adfs-and-the-accesscontrol-service.aspx. Create custom authentication classes A custom authentication component has two parts: An X++ class that implements the AifAuthenticationManager interface and provides configuration information. A.NET class that implements the System.ServiceModel.ServiceAuthenticationManager interface to provide runtime authentication. 31

AifAuthenticationManager interface This X++ interface must be implemented by an X++ authentication manager class. This interface is used by the services framework to get information that is used to configure and deploy the custom authentication runtime component. X++ interface AifAuthenticationManager AifAuthenticationManagerName getname(); str getauthenticationmanagertype(); str getauthorizationpolicytype(); AifAssemblyName getauthenticationmanagerassemblyname(); Map getappsettings(); MenuItemNameDisplay getconfigurationdisplaymenuitem; Interface methods: AifAuthenticationManagerName getname() Returns the friendly name of the component. This is displayed for selection in the ServiceBus configuration form. str getauthenticationmanagertype() Returns the.net type of the WCF custom authentication class in the runtime assembly. str getauthorizationpolicytype() Returns the.net type of the WCF authorization policy class in the runtime assembly. AifAssemblyName getauthenticationmanagerassemblyname() Returns the name of the authentication assembly that contains the WCF custom authentication class. Map getappsettings() Returns custom settings that are required by the.net authentication component at authentication time. These settings are available in the AppSettings section of the web.config file, which is located in the IIS website directory. Returns null if app settings are not required. MenuItemNameDisplay getconfigurationdisplaymenuitem Returns the name of the display menu item for the configuration form of this component. Returns the empty string if no configuration form is available. 32

Custom authentication component A class that implements the following interfaces can perform custom authentication: System.ServiceModel.ServiceAuthenticationManager System.IdentityModel.Policy.IAuthorizationPolicy The System.ServiceModel.ServiceAuthenticationManager interface contains the ReadOnlyCollection method. ReadOnlyCollection<IAuthorizationPolicy> Authenticate( ReadOnlyCollection<IAuthorizationPolicy> authpolicy, Uri listenuri, ref Message message) The implementation of this method can inspect the request message and headers, perform the custom authentication, and set the authenticated principal on the message as a property. The System.IdentityModel.Policy.IAuthorizationPolicy interface has a the properties and the Evaluate method shown in the following example: bool Evaluate( EvaluationContext evaluationcontext, ref Object state ) The implementation of the Evaluate method sets the authenticated principal and identity on the security context of the message. Registering the authentication component Before an authentication component can be used, it must be registered with the Services framework. The registerauthenticationmanager and unregisterauthenticationmanager methods on the AifAuthenticationHelper class must be used to register and unregister the authentication component. Create an X++ job that calls these X++ methods to register/unregister the authentication components. When a component is registered, the.net assembly is uploaded to the database so that it is accessible to all AOS instances. The file path that you use must grant read permissions to the AOS service account. For more information about the AOS service account, see http://technet.microsoft.com/en-us/library/ee355089.aspx and http://technet.microsoft.com/enus/library/ee355089.aspx and http://technet.microsoft.com/en-us/library/jj585430.aspx. The following code shows the methods and describes the parameters: X++ static public void registerauthenticationmanager( AifAuthenticationManagerClass authenticationmanagerclass, FilePath assemblyfolder, boolean updateexisting = false) 33

AuthenticationManagerClass is class ID of the X++ authentication manager class AssemblyFolder is the path of the folder that contains the.net authentication manager assembly. UpdateExisting is the flag indicating that any existing assembly in the database should updated with the assembly in the folder. X++ static public void unregisterauthenticationmanager( AifAuthenticationManagerClass authenticationmanagerclass) authenticationmanagerclass is the class ID of the X++ authentication manager class Encryption key containers Encryption is used to protect confidential data in the web.config file. This requires a machine-level key container to be created and configured on all the involved machines. We have provided scripts for this process. Download the scripts here: http://blogs.msdn.com/b/aif/archive/2013/04/29/aifwindows-azure-service-bus-adapter.aspx. These scripts use the IIS configuration utility aspnet_regiis.exe to manage the key containers. 1. Create an exportable machine-level key container on the IIS computer. Go to the directory where you want to export the container before running this script. In this example we use the root of the C drive. Windows Command Prompt C:\> CreateKeyContainer MyKey 2. Export the key container to an XML file. The following script will export the key container to MyKey.xml. Windows Command Prompt C:\> ExportKeyContainer MyKey 3. Import the key container into each machine (machine running IIS and machine running the AOS). Windows Command Prompt C:\> ImportKeyContainer MyKey MyKey.xml 4. On each machine, grant the appropriate users access to the key containers. For the IIS Machine, this user is the AppPool identity (which is the same as the BC proxy account). For the AOS machine, this is the AOS account (Network Service or domain account). For a Domain account: Windows Command Prompt C:\> GrantAccessToKeyContainer MyKey domain\user 34

For a Network account: Windows Command Prompt C:\> GrantAccessToKeyContainer MyKey 5. Delete the exported MyKey.xml files. In this example, we exported the MyKey file to the root of the C drive. This is important to prevent unauthorized access to the key container. Publish AIF Service using the Service Bus Adapter We are now going to publish the UnreconciledExpense service operation that we created in Create the service operation. Register your Service Bus namespace 1. Open the Microsoft Dynamics AX Client. Click System administration > Setup > Services and Application Integration Framework > Azure Service Bus Configuration. 2. Provide Service Bus details in the Azure Service Bus Configuration form: a. Supply your Azure Service Bus namespace, which was created when you registered the namespace by following instructions in Microsoft Dynamics AX Connector for Mobile Applications. b. Supply your Azure Service Bus issuer name and issuer secret. c. For Deployment website, select the IIS website to deploy the service on. d. For Class name, specify the authentication class that you registered. e. Click Configure. The Mobile Authentication Configuration form is shown. i. Enter the certificate thumbprint (from your ADFS). ii. Click Close. f. For the RSA key container name, type the name of the key container that you created previously in the Encryption key containers section. g. For a description, provide a description for the Service Bus namespace, as shown in the following illustration: 35

h. Click Close. Deploy your AIF service to the Azure Service Bus To create a new port to publish your service on: 1. Click System Administration > Services and Application Integration Framework > Inbound Ports. 2. Click New to create a new port. 3. Type the name of the port. It is a best practice to incorporate the name that you used for the Azure Service Bus namespace on the Azure Service Bus Configuration form (2- a). 4. Type a description of the port to provide a description of the services that this port hosts. 5. Select Azure Service Bus for Adapter. 6. Click the button beside the URI field to open the Select Azure Service Bus Namespace form, and select the namespace that you created. 7. Click OK. 36

8. Click the Service Operations button, which is located below Service Contract customizations. 9. Find the UnreconciledExpense service from Create the expense service operations in the right-hand pane. i. Select all of the operations on your service that you want to publish by highlighting each one, and then clicking the < button. ii. Click Close. 10. In the Inbound Ports form, highlight your port in the left-hand pane. 11. Click Activate. 12. The UnreconciledExpense Service is now published to IIS 7.5. The URL to access the Microsoft Dynamics AX service through the Service Bus is displayed in the URI: field, as shown in the previous illustration. For the example in this document, the URI field should be: https://contosomobile.servicebus.windows.net/unreconciledexpense/xppservice.svc You may now refer to the remainder of this document to develop the client that will communicate with Microsoft Dynamics AX using the AX service that you have published to the Windows Azure Service Bus. 37

Develop the client to communicate data to the middle-tier WCF service In this example and the sample code provided, we have made use of a Windows Phone application to represent a client for the backend service, but you are by no means limited to that. Clients could be anything ranging from Windows 8 apps in or JavaScript to.net services to websites. Development requirements Visual Studio 2010 with Windows Phone SDK 7.1 with the 7.8 update installed, or Visual Studio 2012 with Windows Phone SDK 8.0 installed. The Service Bus component (Microsoft.ServiceBus.dll), which is included with the Windows Azure Libraries for.net. To install it, visit the Windows Azure SDK download page. Overview This section will guide you through creating a Windows Phone client application that will consume the hosted Expense service on the Service Bus. First, you will create a Windows Phone application project and generate a client proxy to consume the middle-tier service. Then you will lay out the controls on the UI for accepting the required input from the user and handling all the control and page events. Create a Windows Phone application Open Visual Studio, and create a Windows Phone app project for example, ContosoMobileApp. For more information about Windows Phone development, see Getting started with developing for Windows Phone. A recommended way for developing Windows Phone apps is to use the MVVM pattern for Windows Phone apps. See Developing a Windows Phone Application using the MVVM Pattern. Add the middle-tier WCF service reference 1. Right-click References, and add a service reference. You will need to enter the MEX URL that was specified in the Create the middle-tier WCF service section. Note: The middle-tier service must be running at this point, and its metadata endpoint must be enabled, so that the client can fetch the metadata of the service and generate the client proxy file (Reference.cs). 38

2. Notice that a ServiceReferences.Clientconfig file is created. Make sure that the following binding information for the client exists. APP.CONFIG <configuration> <system.servicemodel> <bindings> <basichttpbinding> <binding name="basichttprelaybinding_expenseservicecontract" maxbuffersize="2147483647" maxreceivedmessagesize="2147483647"> <security mode="transport" /> </binding> </basichttpbinding> </bindings> <client> <endpoint address="https://contosomobile.servicebus.windows.net/https/expenseservice/" binding="basichttpbinding" bindingconfiguration="basichttprelaybinding_expenseservicecontract" contract="expenseservicereference.expenseservicecontract" name="basichttprelaybinding_expenseservicecontract" /> </client> </system.servicemodel> </configuration> 39

If you want to access your MEX endpoint outside your domain during development, you could also consider hosting the WCF service s MEX endpoint on the Service Bus itself. Lay out and set up the UI controls for required user input After adding the service reference, look at the Reference.cs client proxy file that is generated. You will see a method such as CreateExpenseAsync. This is the service operation that the app will call to send across expense data. As you can see in the generated proxy, the values that need to be passed in are the date, amount, currency string, and comments. public void CreateExpenseAsync( System.DateTime datetime, decimal amount, string currency, string comments) this.createexpenseasync(datetime, amount, currency, comments, null); Also remember that, in addition to sending the expense data, the app is required to do the following: Authenticate to the Service Bus when making the service call. Send the claims that identify the user sending the expense data, in the form of a SAML assertion token. We will walk you through the authentication implementation in the Implement active federation and claims-based authorization for the mobile client section. Based on these requirements, the app gathers the following data from the user: Data for the service operation Data for the authentication 40

Data for the service operation In the app project, create a new page, MainPage.xaml. We will design this page (together with its MainPage.xaml.cs file) to store the expense data. The user enters the expense data and then clicks the Upload button. We will see later how the data is sent across to the service in the UploadClick event handler. 41

Data for the authentication In the app project, create a new page, Settings.xaml. We will design and implement this page (together with its Settings.xaml.cs file) to store the data required for authentication. This data is taken as input from the user. The user name, password, service connection name (Windows Azure namespace), and authentication server URL (the AD FS endpoint) are then used to authenticate the user for the service operations. The next step is to implement active federation for claims-based authentication to the Windows Azure Service Bus by using ACS and AD FS. Implement active federation and claims-based authorization for the mobile client Prerequisites (configuring the trusts) 1. Create the Windows Azure namespace and configure the Service Bus, as explained in Microsoft Dynamics AX Connector for Mobile Applications. 2. Add the Service Bus as the relying party in the ACS. In this way, the ACS is responsible for providing security to the Service Bus. For more information, see the Configuring the Access Control Service; Configure the relying party applications section in Microsoft Dynamics AX Connector for Mobile Applications. 42

3. Set up trust between AD FS 2.0 and the ACS. The Active Directory server acts as the identity provider. It contains information about the corporate users and authenticates a user s identity. Configure AD FS on the Active Directory server. The AD FS is also a security token service (STS) that provides security tokens to requestors. Configure AD FS to trust only requests coming from the ACS of the Service Bus for the namespace that you created. For example, add the endpoint https://contosomobilesb.accesscontrol.windows.net as a relying party in the AD FS by providing the federation metadata URL exposed by the ACS. For more information, see the Configuring an Active Directory Federation Service for authentication section in Microsoft Dynamics AX Connector for Mobile Applications. Configure the ACS to trust claims coming from the AD FS. To do this, go to your namespace s Management Portal for the ACS, and add the AD FS as an identity provider in the Identity Provider configuration section. You will need to add the federation metadata URL exposed by the AD FS server. For more information, see the Configuring the Access Control Service; Add and configure the identity provider section in Microsoft Dynamics AX Connector for Mobile Applications. 4. Map incoming claims to outgoing claims in the ACS. These claims will be inspected by Service Bus. An incoming claim of the windowsaccountname type should be mapped to an outgoing claim of the net.windows.servicebus.action type with a value of Send. (For more information, see the Configuring the Access Control Service; Configure rule groups section in Microsoft Dynamics AX Connector for Mobile Applications.) This will ensure that any authenticated user having the windowsaccountname claim sent by the AD FS is authorized to send a message through the Service Bus. 5. Set up trust between the middle-tier WCF service and the corporate AD FS. The AD FS uses an X.509 token signing certificate issued by a CA to digitally sign the SAML token containing the claims about the user. For more information, see the Configuring an Active Directory Federation Service for authentication; Add/Configure the token signing certificate section in Microsoft Dynamics AX Connector for Mobile Applications. When setting up the trust, observe the following guidelines: Overview The X.509 token signing certificate needs to be installed in the Trusted Root Certification store on the machine that hosts the middle-tier WCF service. The thumbprint of the certificate should be made available to this service. By using this thumbprint, the service can verify that the claims are from an authorized and trusted issuer. After collecting the information from the user on the mobile device, we now need to submit the data to Microsoft Dynamics AX. Only those users who are authenticated are authorized to send this data through the Service Bus to Microsoft Dynamics AX. The ACS and AD FS (which acts as an identity provider and a security token service) cooperate to authenticate and authorize Service Bus operations. The claims obtained from the identity provider are also used to extract information about the user in the middle-tier service. Authorization of Microsoft Dynamics AX users according to their Microsoft Dynamics AX roles and privileges will be handled by the Microsoft Dynamics AX instance itself. We use active federation and the WS-Trust security protocol to request a security token (containing the required claim) from the identity provider (corporate AD FS). After the security token is presented to the ACS, it recognizes the identity of the user. As was mentioned in the prerequisites, the incoming claims are mapped to the Send outgoing claims that are recognized by the Service Bus for which the ACS is providing security. A claim is then issued to the client by the ACS in the form of a simple web token (SWT). 43

When the client is ready to send its message through the Service Bus endpoint, it presents the SWT, thus granting it permission to send the message. For our solution, the client is also required to send across to the middle-tier service, the SAML assertions token that it received from the AD FS. The service then extracts the assertion claims, as we saw in the walkthrough for the middle-tier WCF service. The following steps will show how we implement the required authentication described earlier. Development requirements You can implement the authentication described in the next section in the same Windows Phone app project or in a compatible Windows Phone class library, which you can then reference in the app (if you plan to reuse the authentication code). If you are implementing a client (Windows Phone 8 or Windows 8 Store app) in Visual Studio 2012, consider creating a Portable Class Library for the authentication and including the library in your client application. Implementation We will walk you through implementing the authentication by using sample code to show you how the Expense Capture mobile application uses the SAML and SWT tokens to securely pass data through the Service Bus to Microsoft Dynamics AX. Setup 1. In the phone app (ContosoMobileApp) that we created earlier, create a new class named AuthenticationProvider, and include the System.Net reference in it. using System.Net 2. Create an event for notification about completion of authentication. This event should provide notification about errors and also success in authentication. /// <summary> /// Delegate type for handling authentication completed events /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public delegate void AuthenticationCompletedEventHandler(object sender, AuthenticationMessageArgs e); 44

Here, AuthenticationMessageArgs is a class that defines custom EventArgs for storing custom exception messages and a Boolean value for success. public class AuthenticationMessageArgs: EventArgs public AuthenticationMessageArgs(AuthenticationMessage authenticationmessage) this.authenticationmessage = authenticationmessage; public AuthenticationMessage AuthenticationMessage get; private set; public class AuthenticationMessage public AuthenticationMessage(string message, bool issuccess) this.message = message; this.issuccess = issuccess; public string Message get; set; public bool IsSuccess get; set; /// <summary> /// Subscribe to this event to be notified of authentication completion messages, /// both succeeded & failed. /// </summary> public event AuthenticationCompletedEventHandler AuthenticationCompleted; /// <summary> /// The On Completed method to be called /// </summary> /// <param name="args"></param> private void OnAuthenticationCompleted(AuthenticationMessageArgs args) AuthenticationCompletedEventHandler handler = AuthenticationCompleted; if (handler!= null) handler(this, args); 45

3. Define member variables, such as those for storing the user credentials, and response SAML and SWT tokens. UserCredentials credentials; string azurenamespace = String.Empty; string stsendpoint = String.Empty; string requestsecuritytokenpayload = String.Empty; string requestsecuritytokenresponse = String.Empty; DateTime stsauthstarttime; string acspayload = String.Empty; string samlassertiontoken = String.Empty; string swtacstoken = String.Empty; Get user input The next thing we need to do is accept the user input that is, the user name (in the form domain\user alias), password, Federation Server (AD FS) endpoint URI, and Windows Azure namespace. public AuthenticationProvider( string username, string password, string windowsazurenamespace, string stsendpointurl) credentials = new UserCredentials(userName, password); azurenamespace = windowsazurenamespace; stsendpoint = stsendpointurl; After the Windows Azure namespace is provided, we can define the following endpoints, which are required for the authentication process. /// <summary> /// This read-only property is the relying party that is configured in ADFS. This value tells the STS how /// to respond (which token format, whether it's encrypted, which claims to include, token lifetime, etc.) /// </summary> public string AppliesTo get return "https://" + azurenamespace + "-sb.accesscontrol.windows.net"; /// <summary> /// This read-only property is the actual ACS endpoint we post the SAML token to, to acquire the SWT /// </summary> public string AcsEndPoint 46

get return "https://" + azurenamespace + "-sb.accesscontrol.windows.net/wrapv0.9/"; /// <summary> /// This read-only property is the relying party that's configured in SB's ACS. /// The value is a hint to the STS as to which rules to perform. By default, it's /// http://[namespace].servicebus.windows.net/, but more specific endpoint configurations are /// possible if needed. /// </summary> public string RelyingParty get return "http://" + azurenamespace + ".servicebus.windows.net/"; /// <summary> /// This read-only property is the actual endpoint exposed on ServiceBus that the final service /// call & security tokens will be sent to. /// </summary> public string ServiceEndpoint get return "https://" + azurenamespace + ".servicebus.windows.net/expense/"; 47

Create and send the request for security token Now we can create the request for security token (RST) and actively send the request to the identity provider (AD FS). 1. Create the RST payload. 48 Create a string named StsUrlPayload with the following SOAP message format for the payload. /// <summary> /// This is the actual payload of the SOAP message that will be sent to the STS /// </summary> xmlns:a=""http://www.w3.org/2005/08/addressing"" private string StsUrlPayload = @"<s:envelope xmlns:s=""http://www.w3.org/2003/05/soapenvelope"" xmlns:u=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility- 1.0.xsd""> <!--Header--> <s:header> <a:action s:mustunderstand=""1"">http://docs.oasis-open.org/ws-sx/wstrust/200512/rst/issue</a:action> <a:to s:mustunderstand=""1"">0</a:to> <o:security s:mustunderstand=""1"" xmlns:o=""http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""> <u:timestamp u:id=""_0""> <u:created>1z</u:created> <u:expires>2z</u:expires> </u:timestamp> <o:usernametoken u:id=""uuid-ea4cdc24-712d-4af7-9128-acb3db03b55f-1""> <o:username>3</o:username> <o:password o:type=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wssusername-token-profile-1.0#passwordtext"">4</o:password> </o:usernametoken> </o:security>

</s:header> <s:body> <wsp:appliesto xmlns:wsp=""http://schemas.xmlsoap.org/ws/2004/09/policy""> <a:endpointreference> <a:address>5</a:address> </a:endpointreference> </wsp:appliesto> <trust:requestsecuritytoken xmlns:trust=""http://docs.oasis-open.org/ws-sx/wstrust/200512""> <trust:keytype>http://docs.oasis-open.org/ws-sx/wstrust/200512/bearer</trust:keytype> <trust:requesttype>http://docs.oasis-open.org/ws-sx/wstrust/200512/issue</trust:requesttype> <trust:tokentype>urn:oasis:names:tc:saml:1.0:assertion</trust:tokentype> </trust:requestsecuritytoken> </s:body> </s:envelope>"; 2. Insert the values for the highlighted parts in the StsUrlPayload string, and assign it to requestsecuritytokenpayload. this.stsauthstarttime = DateTime.UtcNow; //Setting Expires time to request time + 5 minutes requestsecuritytokenpayload = String.Format(this.StsUrlPayload, this._stsendpoint, this.stsauthstarttime.tostring("s") + ".000", this.stsauthstarttime.addminutes(5).tostring("s") + ".000", credentials.username, credentials.password, this.appliesto); 49

3. The SendRequestSecurityToken method is used to send the request across to the AD FS. These are asynchronous SOAP message requests, and callback methods are used to write to the request stream and receive the response. /// <summary> /// Create the RST payload containing the user's credentials /// Send the RST to the STS in a SOAP message using HttpWebRequest /// </summary> private void SendRequestSecurityToken() this.stsauthstarttime = DateTime.UtcNow; requestsecuritytokenpayload = String.Format(this.StsUrlPayload, this._stsendpoint, this.stsauthstarttime.tostring("s") + ".000", this.stsauthstarttime.addminutes(5).tostring("s") + ".000", credentials.username, credentials.password, this.appliesto); try HttpWebRequest httpwebrequest = (HttpWebRequest)WebRequest.Create(stsEndpoint); httpwebrequest.contenttype = "application/soap+xml; charset=utf-8"; httpwebrequest.method = "POST"; httpwebrequest.begingetrequeststream( new AsyncCallback(RequestSecurityTokenStreamCallback), httpwebrequest); catch (Exception e) //Fire the event to be handled by the App in case there was an error during authentication OnAuthenticationCompleted(new AuthenticationMessageArgs( new AuthenticationMessage(e.Message,false))); 50

private void RequestSecurityTokenStreamCallback(IAsyncResult asynchronousresult) HttpWebRequest httpwebrequest = (HttpWebRequest)asynchronousResult.AsyncState; Stream requeststream = null; try using (requeststream = httpwebrequest.endgetrequeststream(asynchronousresult)) if (requeststream!= null) byte[] bytes = Encoding.UTF8.GetBytes(requestSecurityTokenPayload); requeststream.write(bytes, 0, bytes.length); httpwebrequest.begingetresponse( new AsyncCallback(RequestSecurityTokenResponseStreamCallback), httpwebrequest); catch (Exception e) OnAuthenticationCompleted(new AuthenticationMessageArgs(new AuthenticationMessage(e.Message, false))); 4. The requestsecuritytokenresponse message contains the SAML token containing the windowsaccountname claim for the user. After extracting the request for security token response (RSTR) (by using the GetResponseStringFromResponse method), we call the SendTokenToAcs method. /// <summary> /// Helper method to extract the response string from an HttpWebResponse object. /// </summary> /// <param name="response">the HttpWebResponse object</param> /// <returns>the response string contained in the http response.</returns> public static string GetResponseStringFromResponse(HttpWebResponse response) string responsestring = string.empty; if (response!= null) Stream streamresponse = null; try streamresponse = response.getresponsestream(); using (StreamReader streamread = new StreamReader(streamResponse)) 51

streamresponse = null; responsestring = streamread.readtoend(); finally if (streamresponse!= null) streamresponse.dispose(); return responsestring; Create the ACS payload 1. The next step is to extract the SAML claims from the RSTR and construct the ACS payload. GetSamlTokenFromResponseString is a utility method that looks for the <saml:assertion> element in the response string and returns the element s contents as the SAML token. public static string GetSamlTokenFromResponseString(string responsestring) string samltoken = string.empty; 52

// Parse the xml to find the <saml:assertion> tag as per SAML11 standard. // This is the ADFS token StringReader reader = null; try reader = new StringReader(responseString); using (XmlReader xmlparser = XmlReader.Create(reader)) finally reader = null; while (xmlparser.read()) switch (xmlparser.nodetype) case XmlNodeType.Element: string name = xmlparser.name; if (String.Equals(xmlparser.Name, "saml:assertion")) break; if (reader!= null) reader.dispose(); return samltoken; samltoken = xmlparser.readouterxml(); /// <summary> /// Extracts the SAML assertions from the RSTR and sends a request to the ACS for a SWT token /// </summary> private void SendTokenToAcs() const string acspayloadformat = @"wrap_scope=0&wrap_assertion=1&wrap_assertion_format=saml"; samlassertiontoken = Utilities.GetSamlTokenFromResponseString(requestSecurityTokenResponse); if (!String.IsNullOrEmpty(samlAssertionToken)) acspayload = String.Format(acsPayloadFormat, Uri.EscapeDataString(RelyingParty), Uri.EscapeDataString(samlAssertionToken)); 53

try HttpWebRequest request = (HttpWebRequest)WebRequest.Create(AcsEndPoint); request.contenttype = @"application/x-www-form-urlencoded"; request.method = "POST"; request.begingetrequeststream( new AsyncCallback(RequestAcsTokenStreamCallback), request); catch (WebException e) OnAuthenticationCompleted(new AuthenticationMessageArgs( new AuthenticationMessage(e.Message, false))); else OnAuthenticationCompleted(new AuthenticationMessageArgs( new AuthenticationMessage("SAML Token from STS is empty", false))); 2. The ACS payload containing the SAML token is written to the request stream and sent to the ACS endpoint. private void RequestAcsTokenStreamCallback(IAsyncResult asynchronousresult) HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState; Stream requeststream = null; try using (requeststream = request.endgetrequeststream(asynchronousresult)) if (requeststream!= null) byte[] bytes = Encoding.UTF8.GetBytes(acsPayload); requeststream.write(bytes, 0, bytes.length); request.begingetresponse(new AsyncCallback(RequestAcsTokenResponseCallback), request); catch (WebException e) OnAuthenticationCompleted(new AuthenticationMessageArgs(new AuthenticationMessage(e.Message, false))); 54

3. The ACS sends back a response containing the SWT security token that is required to authenticate to the Service Bus. private void RequestAcsTokenResponseCallback(IAsyncResult asynchronousresult) HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState; try HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult); string rawacsresponse = Utilities.GetResponseStringFromResponse(response); SwtAcsToken = Uri.UnescapeDataString(rawAcsResponse.Split('&').Single(value => value.startswith("wrap_access_token=", StringComparison.OrdinalIgnoreCase)).Split('=')[1]); if (!String.IsNullOrEmpty(this.SwtAcsToken)) OnAuthenticationCompleted(new AuthenticationMessageArgs(new AuthenticationMessage("Security Token from ACS issued successfully", true))); catch (WebException e) // The ACS server has likely sent back an error response string responsestring = Utilities.GetResponseStringFromResponse((HttpWebResponse)e.Response); OnAuthenticationCompleted(new AuthenticationMessageArgs( new AuthenticationMessage(responseString, false))); catch (System.FormatException) // Error parsing ACS token; it is in an invalid format OnAuthenticationCompleted(new AuthenticationMessageArgs( new AuthenticationMessage("Invalid ACS Token Format", false))); catch (System.ArgumentOutOfRangeException) // Error parsing ACS token; it is in an invalid format OnAuthenticationCompleted(new AuthenticationMessageArgs( new AuthenticationMessage("Invalid ACS Token Format", false))); catch (Exception e) OnAuthenticationCompleted(new AuthenticationMessageArgs( new AuthenticationMessage(e.Message, false))); The SwtAcsToken value is extracted from the raw response string sent by the ACS, as shown in the preceding code. 55

At this point a non-empty SWT with no other errors or exceptions implies that the authentication was successful. Additional notes and guidelines To keep this exercise as simple and focused as possible, this code has been boiled down to its essence and only contains the key principles required to understand the solution. In a production-level application, you would want to take into account additional considerations, including your platform and functional requirements. For example, your app does not have to request fresh tokens from both IdPs every time it needs to make a service call. Because of this, it would be useful to implement some local storage or caching of the security tokens until their expiration time. That expiration time is adjustable on both AD FS and the ACS. Choose a token lifetime that makes sense for your scenario and security requirements; for example, more business-sensitive applications should have shorter token lifetimes, whereas low business-impact applications could have longer token lifetimes. Regarding platform support, if you have access to the WIF libraries (for example, if you are writing a.net client), feel free to use them, because they will offer you slightly more robust RST and RSTR processing. If you are working on any other platform, you may either search for library support on that platform or follow the same pattern that you have implemented earlier. Finally, when storing data in durable storage, always be sure to encrypt secret information, such as the user s credentials; this includes the security tokens and even the Service Bus secrets in the app.config file. Authenticate the user and send the data to the service After authenticating the user by using active federation as described in the Implement active federation and claims-based authorization for the mobile client section, the client can send its request to the service endpoint. We now need to use the AuthenticationProvider object within the Windows Phone app. 1. As is shown in the ContosoMobileApp application, when the user clicks the Submit/Save button, we will handle the UploadClick event in the following way. private void UploadClick(object sender, EventArgs e) Submit(); 2. In the Submit method, we initialize the AuthenticationProvider object, subscribe to its AuthenticationCompleted event, and then call the IssueToken method. We pass in the user data that we collect from the Settings.xaml page to initialize the AuthenticationProvider object; the following code shows an example of the user input that can be passed in. 56

The IssueToken method is the starting point for the multiple asynchronous calls. public void Submit() // parameters are domain\\useralias, user's password, Azure Namespace & ADFS endpoint URL authenticator = new AuthenticationProvider("contoso\\userAlias", "password", "contosmobile", "https://contosoadfs.com/adfs/services/trust/13/usernamemixed"); authenticator.authenticationcompleted += authenticator_authenticationcompleted; authenticator.issuetoken(); /// <summary> /// Handle the Authentication completed event and then submit the expense using the tokens /// if the authentication was successful /// </summary> private void authenticator_authenticationcompleted(object sender, AuthenticationMessageArgs e) if (e.authenticationmessage.issuccess) else // Authentication was successful. Now submit the expense through service bus, // using the SWT and SAML token values exposed by the AuthenticationProvider CreateExpense(); RaiseSubmitCompleted(new Exception(e.AuthenticationMessage.Message)); 57

3. After the IssueToken asynchronous method is completed, the AuthenticationCompleted event is fired. We then check whether the authentication was successful. If the authentication was successful, the app is now in possession of the SWT (the token to authenticate to the Service Bus) and the SAML token (the token containing the windowsaccountname claim that is used to set the call context of the AIF service call). We then insert the two tokens into a custom SOAP header of the message. The body of the message will contain the expense data we want to send to the middle-tier WCF service. 4. Add a method named CreateExpense that creates the message as described in the previous step and sends it to the actual service endpoint on the Service Bus that is, https://<azurenamespace >servicebus.windows.net/expense/. A call is then made to the CreateExpenseAsync service operation by using the middle-tier service s ExpenseServiceContractClient client proxy. private void CreateExpense() ExpenseServiceReference.ExpenseServiceContractClient expenseservice = new ExpenseServiceReference.ExpenseServiceContractClient(); expenseservice.endpoint.address = new System.ServiceModel.EndpointAddress( new Uri(SettingsViewModel.ServiceEndpoint)); expenseservice.createexpensecompleted += new EventHandler<CreateExpenseCompletedEventArgs>(OnCreateExpenseCompleted); // Get the channel context scope so we can add message headers to it using (new OperationContextScope(expenseService.InnerChannel)) 58

// Grab the raw SAML token and stuff it in a byte array byte[] bintoken = Encoding.UTF8.GetBytes(authenticator.SamlAssertionToken); // Add the SAML token to a custom SOAP header var customsecurityheader = MessageHeader.CreateHeader("PassthroughBinarySecurityToken", "", Convert.ToBase64String(binToken)); OperationContext.Current.OutgoingMessageHeaders.Add(customSecurityHeader); // Add the SWT token to a SOAP header as SB is expecting OperationContext.Current.OutgoingMessageHeaders.Add( new AcsHeader(authenticator.SwtAcsToken)); // Finally, call the actual service to create our expense. expenseservice.createexpenseasync( ExpenseDate, Amount, Amount == 0? null : Currency, Comment); /// <summary> /// This is the Custom (SOAP header) format that Service Bus requires a token /// from ACS to exist in the message. This header will be stripped out by SB /// and thus will not exist when the message gets to the service. /// </summary> /// <remarks> /// Leave all these hard-coded values alone, SB is expecting /// a very particular format for this header. /// </remarks> private class AcsHeader : MessageHeader private string token; public AcsHeader(string token) this.token = token; public override string Name get return "RelayAccessToken"; public override string Namespace get return "http://schemas.microsoft.com/netservices/2009/05/servicebus/connect"; 59

protected override void OnWriteHeaderContents( XmlDictionaryWriter writer, MessageVersion messageversion) writer.writestartelement("binarysecuritytoken", "http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); writer.writeattributestring("id", "http://docs.oasis-open.org/wss/2004/01/oasis- 200401-wss-wssecurity-utility-1.0.xsd", string.format("uuid:0", Guid.NewGuid().ToString("D"))); writer.writeattributestring("valuetype", "http://schemas.xmlsoap.org/ws/2009/11/swttoken-profile-1.0"); writer.writeattributestring("encodingtype", "http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#base64binary"); byte[] bintoken = Encoding.UTF8.GetBytes(token); writer.writebase64(bintoken, 0, bintoken.length); writer.writeendelement(); The request is then sent to the endpoint on the Service Bus. The Service Bus authorizes the incoming message to be relayed through it to the middle-tier WCF service, by examining the SWT. The expense data and the SAML token are then passed to the middle-tier service. The Service Bus also relays back the response from the WCF service after the operation is completed. An event is raised to notify about completion. In this example, you can also create a custom completed notification event to handle the response (success or error messages) within the application and send a message that can be viewed by the user. In the preceding code sample, we subscribe to a custom event, CreateExpenseCompleted, to accomplish this. Developing RESTful JavaScript mobile apps for Microsoft Dynamics AX 2012 Creating secure mobile apps for Microsoft Dynamics AX 2012 is not restricted to clients that are built on the.net runtime, such as Windows Phone and Windows Store apps. As we indicated earlier, you can also create mobile apps by using cross-platform technologies such as HTML5 and JavaScript. The solution architecture for creating such apps remains the same, as described in the Technical overview section. This means that you can still create secure apps for mobile clients by using active federation and claims-based identity for authentication, given the user s corporate credentials and using the Windows Azure Service Bus relay to transport the messages from the client to the middletier WCF service, which in turn would send the data across to Microsoft Dynamics AX by using AIF services. 60

The following table demonstrates a mapping between apps that use the.net Framework and apps that use HTML5 and JavaScript with respect to the various components in the architecture. Microsoft Dynamics AX AIF service Middle-tier WCF service Configuration (AD FS, Windows Azure Service Bus, ACS) Active federation for authentication Fetching tokens, claims, and communication to the WCF service Mobile client UI.NET Framework Creating AIF services is described in the Design and create the AIF service in Microsoft Dynamics AX 2012 section. A SOAP-based service with a BasicHttpRelayBinding binding. The SAML token is in the SOAP header. The configuration required for setting up AD FS, token signing certificates, and the Windows Azure Service Bus and ACS is described in Microsoft Dynamics AX Connector for Mobile Applications. Implemented by using.net technologies (WCF and System.NET APIs). For more information, see the Implement active federation and claims-based authorization for the mobile client section. Implemented by using.net technologies (WCF and System.NET APIs). The SAML token with claims is sent in a custom SOAP header, together with the SWT for the Service Bus. For more information, see the Authenticate the user and send the data to the service section. Accepts user input. Implemented by using.net technologies (for example, for Windows Phone and Windows Store apps). HTML5/JavaScript No change A RESTful service with a WebHttpRelayBinding binding. The SAML token is in the request body. No change No change in request payloads to AD FS. Implemented by using JavaScript and JQuery for asynchronous communication. No change in the request for a SWT sent to the ACS. However, the SAML token is sent in the request body of the JSON payload. The SWT is sent in the HTTP Authorization header. Accepts user input. Can be implemented by using HTML5, for example. The following walkthrough provides guidance in creating RESTful JavaScript mobile apps and uses the same expense capture example that was used in earlier sections. Design and create the AIF service in Microsoft Dynamics AX 2012 The steps to create the AIF service for our expense example remain the same as described in the Design and create the AIF service in Microsoft Dynamics AX 2012 section. Create the middle-tier RESTful service This section will now walk you through creating a RESTful service by using WCF. You can create this service in a way that is very similar to the WCF SOAP service that we created in the Create the middle-tier WCF service section, except that we now create and configure the service to deploy RESTful service endpoints on the Service Bus. Before you complete this walkthrough, you could also see the Create the middle-tier WCF service section to help you understand the following: Setting up the Service Bus relay and deploying the listening endpoint 61

Using Windows Identity Foundation to validate incoming messages and extract the user s claims Adding the AIF service reference Building and creating an installer, and deploying the Windows service Prerequisites An X.509 token signing certificate is installed on the AD FS server and on the machine running the WCF service, in the Trusted Root Certification Authorities store. For guidance, see Microsoft Dynamics AX Connector for Mobile Applications. You have the thumbprint from that certificate. A Windows Azure Service Bus namespace has been created, and the shared secret and issuer name for the namespace are available. For guidance, see Microsoft Dynamics AX Connector for Mobile Applications. The machine that the middle-tier WCF service runs on should be in the same domain or on the same network as the Microsoft Dynamics AX 2012 AOS machine (which can be the same machine or a different one). Development requirements Visual Studio 2010 and the.net Framework version 4 The Service Bus component (Microsoft.ServiceBus.dll), which is included with the Windows Azure Libraries for.net. To install it, visit the Windows Azure SDK download page. The Windows Identity foundation runtime, which can be downloaded from Windows Identity Foundation SDK. Download the 4.0 version for Visual Studio 2010 and the.net Framework version 4.0. For more information about the WIF SDK, see Windows Identity Foundation SDK. Create the data contract, service contract, and operation contract 1. Open Visual Studio, and create a new Windows Service.NET Framework version 4 project named ExpenseConnectorService. 2. Add the System.ServiceModel.Web reference to the project. 3. Rename the Service1.cs class ConnectorService.cs. This class contains the OnStart and OnStop methods for the Windows service, which we will use to open a listening endpoint. 62

4. Include the System.ServiceModel.Web namespace in this class. using System; using System.ServiceModel.Web; using System.ServiceProcess; namespace ExpenseConnectorService public partial class ConnectorService : ServiceBase private WebServiceHost host; public ConnectorService() InitializeComponent(); protected override void OnStart(string[] args) // Deploy the endpoint protected override void OnStop() // Close the endpoint connection 5. Add the System.Runtime.Serialization reference to the project. 6. Add a new class for the data contract, named ExpenseData, to the project, and include the System.Runtime.Serialization namespace. Add the data members to this serializable object, as shown here. [DataContract] public class ExpenseData [DataMember] public decimal Amount get; set; [DataMember] public string Comments get; set; [DataMember] public string CurrencyCode get; set; [DataMember] public string Date get; set; 63

7. Add the System.ServiceModel reference to the project. 8. Add a new interface for the service contract, named IExpenseRestService, to the project, and create the service contract and operation contract as shown here. Include the System.ServiceModel namespace. [ServiceContract(Name="ExpenseRestServiceContract", Namespace = "http://samples.microsoft.com/dynamicsax/")] public interface IExpenseRestServiceContract [OperationContract] long CreateExpense(string adfstoken, ExpenseData expensedata); 9. Create another class for the service operation implementation, which implements IExpenseRestServiceContract. Include the System.ServiceModel.Web namespace in this class. using System; using System.IO; using System.Linq; using System.ServiceModel.Web; using System.Xml; namespace ExpenseConnectorService public class ExpenseRestService: IExpenseRestServiceContract [WebInvoke( UriTemplate = "Expense?Action=Create", // URI:"https://<azurenamespace>.servicebus.windows.net/ExpenseRestService/Expense?Ac tion=create" RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)] public long CreateExpense(string adfstoken, ExpenseData expensedata) // Implementation 10. The CreateExpense service operation needs to be handled by the WCF REST programming model. To do this, we need to specify the following: WebInvoke attribute for the service operation: This lets us map the service operation to the HTTP verb POST and place the SAML token in the body of the HTTP request. UriTemplate: This is the URI that is mapped to the operation that the client will send its request to. The endpoint that we deploy on the Service Bus will be in the form https://<azurenamespace>.servicebus.windows.net/expenserestservice, and therefore the CreateExpense service operation will be mapped to https://<azurenamespace>.servicebus.windows.net/expenserestservice/expense?action=cre ate, as shown in the preceding code. 64

RequestFormat and ResponseFormat: These indicate that we will be sending messages to and from the client in the form of JSON payloads. Observe the two parameters in the service operation. The first is adfstoken, which is the SAML token that is acquired from the corporate AD FS by the client. This token contains the windowsaccountname claim that identifies the user making the request and will be used to set the CallContext property when the AIF service call is made. For more information about the CallContext property, see the Call the AIF service operations section. The second parameter is data that comes from the client. This contains the expense data we defined in the serializable data contract. Both these parameters exist in the incoming JSON body of the payload. Add a service reference of the AIF service See the Add a service reference of the AIF service section. Call the AIF service operations Create a new private method named SubmitExpenseToAX. For this example, pass in the windowsaccountname string and the ExpenseData object. For more information, see the Call the AIF service operations section. private long SubmitExpenseToAX(ExpenseData expensedata, string windowsaccountname) UnreconciledExpenseRecord record = new UnreconciledExpenseRecord() ; parmnotes = expensedata.comments, parmtransactioncurrencyamount = expensedata.amount, parmtransactiondate = DateTime.Parse(expenseData.Date), parmtransactioncurrencycode = expensedata.currencycode using (UnreconciledExpenseServiceClient client = new AXExpenseServiceReference.UnreconciledExpenseServiceClient()) UnreconciledExpenseRecord expenserecord = record; CallContext callcontext = new CallContext() LogonAsUser = windowsaccountname ; return client.createrecord(callcontext, expenserecord); Configure the RESTful service bindings and deploy the listening endpoint on Service Bus The Set up the Service Bus relay and deploying the listening endpoint for the middle-tier WCF service section describes in detail the bindings required for a SOAP service to communicate with the Service Bus. In a very similar way, we need to set up a WebHttpRelayBinding binding to deploy the RESTful service s listening endpoint on the Service Bus. You will need to update the app.config file to add the binding and specify the Service Bus credentials. 65

1. Define the WebHttpRelayBinding configuration by adding the following under the <bindings> element in the <system.servicemodel> section. Set the relayclientauthenticationtype parameter to RelayAccessToken, which forces clients of the service to authenticate to the Service Bus before sending across any messages. APP.CONFIG <bindings> <webhttprelaybinding> <binding name="webhttprelaybinding_servicebus"> <security mode="transport" relayclientauthenticationtype="relayaccesstoken"/> </binding> </webhttprelaybinding> </bindings> 2. Define configuration values for the endpoint behavior. APP.CONFIG <behaviors> <endpointbehaviors> <behavior name="sharedsecretclientcredentials"> <transportclientendpointbehavior credentialtype="sharedsecret"> <clientcredentials> <!-- The issuername & issuersecret here should be set to the values for the service account on Service Bus you wish to use to listen. By default, the namespace will come with an admin user (issuername) of "owner" with a 256-bit secret key (issuersecret) available in the Windows Azure management portal. --> <sharedsecret issuername="owner" issuersecret="xxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxx="/> </clientcredentials> </transportclientendpointbehavior> </behavior> </endpointbehaviors> </behaviors> 66

3. Deploy the listening endpoint. Add the following code snippet in the app.config file, under the <services> element. APP.CONFIG <services> <service name="expenseconnectorservice.expenserestservice"> <endpoint address="" behaviorconfiguration="sharedsecretclientcredentials" binding="webhttprelaybinding" contract="expenseconnectorservice.iexpenserestservicecontract"/> <host> <baseaddresses> <!-- This baseaddress should be set to the URI you intend to listen to on the Service Bus. It should be of the form: "https://<appfabric_namespace>.servicebus.windows.net/expense/" --> <add baseaddress="https://contosomobile.servicebus.windows.net/expenserest/"/> </baseaddresses> </host> </service> </services> 4. We also need to update the app.config file to register the preceding Service Bus behavior and binding extensions. APP.CONFIG <extensions> <behaviorextensions> <add name="transportclientendpointbehavior" type="microsoft.servicebus.configuration.transportclientendpointbehaviorelement, </behaviorextensions> Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <bindingextensions> <add name="webhttprelaybinding" type="microsoft.servicebus.configuration.webhttprelaybindingcollectionelement, </bindingextensions> </extensions> Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 67

5. Finally, open the Service Bus connection, and start listening on the endpoint. Add the following code snippets to the OnStart method in the ConnectorService class. protected override void OnStart(string[] args) // Note that all binding, endpoint, service, behavior configuration // for this WebServiceHost is located in the app.config host = new WebServiceHost(typeof(ExpenseConnectorService.ExpenseRestService)); WriteToEventViewer("Opening the Service endpoint connection " + host.baseaddresses[0].tostring()); try host.open(); WriteToEventViewer(string.Format("Listening on: 0", host.description.endpoints.find( typeof(expenseconnectorservice.iexpenserestservicecontract)).address)); catch (Exception e) WriteToEventViewer(e.Message); private void WriteToEventViewer(string eventmessage) string source = "Expense WCF Service"; if (!EventLog.SourceExists(source)) EventLog.CreateEventSource(source, "Application"); EventLog.WriteEntry(source, eventmessage, EventLogEntryType.Information); protected override void OnStop() host.close(); Validate and extract contents from incoming JSON messages The Validate and extract contents from incoming messages section explains, in detail, more about the SAML token and the claims extracted, and also the use of WIF to validate the token from the trusted issuer. You will need to process the incoming JSON message to extract the claims and the expense data. The client sends a POST request containing the parameter values for adfstoken and expensedata in the request body itself;, therefore, you can easily extract the claims from the adfstoken parameter and the ExpenseData object from the expensedata parameter. 68

You will also need to add the configuration required by Windows Identity Foundation to handle the incoming SAML tokens (that is, the thumbprint for the X.509 token signing certificate, as described in the Validate and extract contents from incoming messages section). 1. Update the app.config file under the <configuration> node, adding configuration values for handling the SAML security token issued by the AD FS. The issuer (also known as the identity provider in our case, the corporate AD FS) uses a token signing certificate to digitally sign the SAML token. APP.CONFIG <microsoft.identitymodel> <service> <securitytokenhandlers> <securitytokenhandlerconfiguration> <audienceuris mode="never"/> <issuernameregistry type="microsoft.identitymodel.tokens.configurationbasedissuernameregistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <trustedissuers> <!-- The STS that issues the SAML token exchanged at ACS must be added as a trusted issuer here. The thumbprint & name values should be obtainable from the public signing certificate exposed on the STS' federation metadata --> <add thumbprint="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" name=""/> </trustedissuers> </issuernameregistry> </securitytokenhandlerconfiguration> </securitytokenhandlers> </service> </microsoft.identitymodel> APP.CONFIG <configsections> <section name="microsoft.identitymodel" type="microsoft.identitymodel.configuration.microsoftidentitymodelsection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </configsections> 2. Add Microsoft.IdentityModel and System.IdentityModel references to the project, and add the following namespaces to the ExpenseRestService.cs file. using System.IdentityModel.Tokens; using System.Security.Principal; using Microsoft.IdentityModel.Claims; using Microsoft.IdentityModel.Configuration; 69

3. Add an implementation to the CreateExpense service operation to do the following: 1. Extract the security token containing the SAML assertions from the adfstoken parameter value. This information is passed by the mobile client calling the service. 2. Use WIF to validate the token by using the thumbprint and other configuration values from the service configuration. 3. Extract the required claim (windowsaccountname) from the token. 4. Make the call to the SubmitExpenseToAX method, which will make the AIF service call. Pass the expensedata value in the call that will be sent to the AIF service. [WebInvoke( UriTemplate = "Expense?Action=Create", // URI:"https://<azurenamespace>.servicebus.windows.net/ExpenseRestService/Expense?Action =Create" RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)] public long CreateExpense(string adfstoken, ExpenseData expensedata) string windowsaccountname = string.empty; // Extract the 'adfstoken' from the message body string samltokenstring = Uri.UnescapeDataString(adfsToken); // Load the app.config settings where we specify the audience & issuer that we'll // accept in a token var config = new ServiceConfiguration(); var handler = config.securitytokenhandlers[ Microsoft.IdentityModel.Tokens.SecurityTokenTypes.Saml11TokenProfile11]; ClaimsIdentityCollection claimsidentity = null; // Convert the raw token into something that can be inspected using (XmlReader reader = XmlReader.Create(new StringReader(samlTokenString))) SecurityToken token = handler.readtoken(reader); // This is the primary WIF call that // 1) Performs all the token validation // a. Format, token type, key type, version, etc. // b. Expiration // c. Audience/AppliesTo/Relying party // d. Issuer // e. Signature // 2) generates a ClaimsIdentityCollection that contains what the app actually // cares about claimsidentity = handler.validatetoken(token); 70

IPrincipal principal = new ClaimsPrincipal(claimsIdentity); IClaimsIdentity identity = (IClaimsIdentity)principal.Identity; windowsaccountname = identity.claims.single(claim => claim.claimtype == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname").value; return SubmitExpenseToAX(expenseData, windowsaccountname); Create an HTML5/JavaScript app to communicate data to the WCF middle-tier RESTful service Mobile apps can be created by using commonly known web technologies, such as HTML5, CSS3, and JavaScript. HTML5 and style sheets can be combined to produce impressive user interfaces, which you can use to obtain user input. In our expense capture example, the client could be designed to capture the following user input: Expense data, such as the amount, currency, date, and comments Authentication data, such as the following: The user s alias and password The Windows Azure Service Bus namespace hosting the back-end service s endpoint The endpoint URL of the AD FS server that is required for active federation This document will not cover the creation of the user interface itself, but will instead focus on the client-side authentication and service calls. Implement active federation and claims-based authorization for the mobile client by using JavaScript We now move on to implementing the authentication required for communicating to the back-end middle-tier RESTful service through the Service Bus. To help understand more about the authentication process, the prerequisites, and the configuration of trusts between AD FS and the ACS, the ACS and the Service Bus, and AD FS and the middle-tier WCF service, see the Implement active federation and claims-based authorization for the mobile client section. The code samples below will demonstrate how you can achieve the following in JavaScript (using AJAX for asynchronous communication): Send AD FS a request for security token (RST) containing the user s credentials Extract the claim (SAML token) from the request for security token response (RSTR) returned from the AD FS Send a request containing the claim token in exchange for a simple web token (SWT) from the Service Bus s ACS. Extract the SWT from the response received from the ACS. 71

In the following sample, we define a JavaScript AuthenticationProvider object that contains methods for fetching the SAML token from AD FS and the SWT from the ACS. JAVASCRIPT function AuthenticationProvider() // ADFS token variables var _ADFSEndpoint = 'https://contosoadfs.com/adfs/services/trust/13/usernamemixed'; var _ADFSEncodedToken = ''; var _ACSEncodedToken = ''; // user credentials (to be obtained from the user interface) var _username = 'contoso\\useralias'; var _password = 'password'; // Azure namespace var _servicenamespace = 'contosomobile'; // Gets encoded SAML Token from ADFS in response to the Request for Security Token (RST) this.getadfstoken = function getadfstoken(success, error) // prepare parameters for the web-service call var ADFSUrlPayload = ["<s:envelope xmlns:a='http://www.w3.org/2005/08/addressing\' xmlns:s='http://www.w3.org/2003/05/soap-envelope'>", "<s:header>", "<a:action s:mustunderstand='1'>http://docs.oasisopen.org/ws-sx/ws-trust/200512/rst/issue</a:action>", "<Security s:mustunderstand='1' xmlns:u='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'", " xmlns='http://docs.oasis-open.org/wss/2004/01/oasis- 200401-wss-wssecurity-secext-1.0.xsd'>", "<UsernameToken u:id='45dcb005-1a5b-4c9d-b26ecb9ab35f7b26'>", "<Username>", _username, "</Username>", "<Password Type='http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'>", _password, "</Password>", "</UsernameToken>", "</Security>", "<a:to s:mustunderstand='1'>", _ADFSEndpoint, "</a:to>", "</s:header>", "<s:body>", "<trust:requestsecuritytoken xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>", "<wsp:appliesto xmlns:wsp='http://schemas.xmlsoap.org/ws/2004/09/policy'>", sb.accesscontrol.windows.net/</a:address>", "<a:endpointreference>", "<a:address>https://", _servicenamespace, "- "</a:endpointreference>", "</wsp:appliesto>", "<trust:keytype>http://docs.oasis-open.org/ws-sx/wstrust/200512/bearer</trust:keytype>", "<trust:requesttype>http://docs.oasis-open.org/wssx/ws-trust/200512/issue</trust:requesttype>", "</trust:requestsecuritytoken>", 72

JAVASCRIPT "</s:body>", "</s:envelope>"].join(""); // Ajax call to send the request to AD FS $.ajax( url: _ADFSEndpoint + "/", type: "POST", contenttype: "application/soap+xml", datatype: "xml", data: ADFSUrlPayload, success: function (data, textstatus, jqxhr) var response = jqxhr.responsetext; // Get the SAML assertion token from the response var startindex = response.indexof("<saml:assertion"); if (startindex!= -1) var endindex = response.indexof("/saml:assertion"); var _ADFSRawToken = response.substring(parseint(startindex), (parseint(endindex) + parseint(16))); _ADFSEncodedToken = encodeuricomponent(_adfsrawtoken); ); // Fire the successful event if (success && $.isfunction(success)) success(_adfsencodedtoken);, error: function (jqxhr, textstatus, errorthrown) // Fire the failure event if (error && $.isfunction(error)) error(textstatus, errorthrown); // Get the ACS SWT token by sending the ACS the ADFSEncodedToken containing the identity // claims about the user (windowsaccountname) in a specific format this.getacstoken = function getacstoken(success, error) $.ajax( type: "POST", url: "https://" + _servicenamespace + "-sb.accesscontrol.windows.net/wrapv0.9/", contenttype: "application/x-www-form-urlencoded", data: 'wrap_scope=http%3a%2f%2f' + _servicenamespace + '.servicebus.windows.net%2f&wrap_assertion=' + _ADFSEncodedToken + '&wrap_assertion_format=saml', datatype: "text", success: function (data, textstatus, jqxhr) var response = decodeuricomponent(jqxhr.responsetext); 73

JAVASCRIPT // Get the SWT token from the response var endindextoken = response.indexof('&wrap_access_token_expires_in'); _ACSEncodedToken = response.substring(18, endindextoken); ); // Fire the successful event if (success && $.isfunction(success)) success(_acsencodedtoken);, error: function (jqxhr, textstatus, errorthrown) // Fire the failure event if (error && $.isfunction(error)) error(textstatus, errorthrown); Send the request payload to the REST service After the expense data is captured from the user, the data, together with the authentication tokens, needs to be sent in the request to the back-end service operation CreateExpense. In the following code sample, we create a ServiceRequest object whose send method does the following: Create a request message containing the SWT in the header, and the SAML token together with the user data (expense data in our example), in the request body Send the message to the endpoint URI of the RESTful service operation through the Service Bus relay. JAVASCRIPT function ServiceRequest() this.send = function send(adfsencodedtoken, acsencodedtoken, success, error) // Create the payload for the RESTful service at the backend containing the expensedata // and the adfstoken var expenseobj = "Amount": "100", "Comments": "Expense of 100 EUR", "CurrencyCode": "EUR", "Date": "02/02/2013" ; var payload = "adfstoken": adfsencodedtoken, "expensedata": expenseobj ; // The token sent to Service Bus relay needs to be in a particular format 74

JAVASCRIPT var relaytoken = 'WRAP access_token="' + acsencodedtoken + '"'; var payloadjson = JSON.stringify(payload); // Make the AJAX call to invoke the service operation mapped to a specific URL // The relay token goes into the header of the request going through Service Bus $.ajax( type: "POST", url: 'https://contosomobile.servicebus.windows.net/expenserestservice/expense?action=create', ); beforesend: function (jqxhr), jqxhr.setrequestheader('authorization', relaytoken); contenttype: 'application/json; charset=utf-8', data: payloadjson, processdata: false, datatype: "json", success: function (data, textstatus, jqxhr), // Fire the success event if (success && $.isfunction(success)) success(data); error: function (jqxhr, textstatus, errorthrown) // Fire the failure event if (error && $.isfunction(error)) error(textstatus, errorthrown); Finally, use the AuthenticationProvider object implemented earlier to begin the series of asynchronous calls to the getadfstoken and getacstoken methods, and then send across the request to invoke the service operation in the middle-tier service. JAVASCRIPT <script type="text/javascript"> var adfstoken = ''; var acstoken = ''; var authprovider = new AuthenticationProvider(); //Fire off the asynchronous calls on clicking a submit button for example $('#submit').click(function (evt) //Support cross domain requests $.support.cors = true; authprovider.getadfstoken(adfssuccess, adfserror); ); var adfserror = function (textstatus, errorthrown) console.log(textstatus + ": " + errorthrown); 75

JAVASCRIPT var adfssuccess = function (_ADFSEncodedToken) adfstoken = _ADFSEncodedToken; authprovider.getacstoken(acssuccess, acserror); var servicerequest = new ServiceRequest(); var acserror = function (textstatus, errorthrown) console.log(textstatus + ": " + errorthrown); var acssuccess = function (_ACSEncodedToken) acstoken = _ACSEncodedToken; servicerequest.send(adfstoken, acstoken, submitsuccess, submiterror); var submitsuccess = function (result) console.log("success!"); var submiterror = function (textstatus, errorthrown) console.log(textstatus + ": " + errorthrown); </script> 76

Additional resources Microsoft Dynamics AX Connector for Mobile Applications Walkthrough: Exposing an X++ Class as a Data Contract [AX 2012] Walkthrough: Creating a Windows Service Application in the Component Designer Specify the.net Business Connector proxy account [AX 2012] Getting started with developing for Windows Phone Developing a Windows Phone Application using the MVVM Pattern Download Windows Azure Download Windows Identity Foundation SDK Windows Identity Foundation SDK 77

The computer code, including developer tools and sample code ( software ) included with this document is made available to you under the software license agreement that appear below. Microsoft Dynamics AX Sample License This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. 1. Definitions The terms reproduce, reproduction, derivative works, and distribution have the same meaning here as under U.S. copyright law. A contribution is the original software or any additions or changes to the software. A contributor is any person that distributes its contribution under this license. Licensed patents are a contributor s patent claims that read directly on its contribution. 2. Grant of Rights (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. 3. Conditions and Limitations (A) No Trademark License - This license does not grant you rights to use any contributors name, logo, or trademarks. (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. (E) The software is licensed as-is. You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. (F) Platform Limitation- The licenses granted in sections 2(A) & 2(B) extend only to the software or derivative works that operates with Microsoft Dynamics AX. 78

Microsoft Dynamics is a line of integrated, adaptable business management solutions that enables you and your people to make business decisions with greater confidence. Microsoft Dynamics works like and with familiar Microsoft software, automating and streamlining financial, customer relationship, and supply chain processes in a way that helps you drive business success. U.S. and Canada Toll-Free 1-888-477-7989 Worldwide +1-701-281-6500 www.microsoft.com/dynamics This document supports a demonstration of how to create a mobile app for use with Microsoft Dynamics 2012. This document is provided for informational purposes only and Microsoft makes no warranties, either express or implied, in this document. Information in this document, including URL and other Internet Web site references, is subject to change without notice. The entire risk of the use or the results from the use of this document remains with the user. Unless otherwise noted, the companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted in examples herein are fictitious. No association with any real company, organization, product, domain name, e-mail address, logo, person, place, or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. This is a preliminary document and may be changed substantially prior to final commercial release of the software described herein. The information contained in this document represents the current view of Microsoft Corporation on the issues discussed as of the date of publication. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication. This white paper is for informational purposes only. Microsoft makes no warranties, express or implied, in this document. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in, or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2013 Microsoft Corporation. All rights reserved. The example companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted herein are fictitious. No association with any real company, organization, product, domain name, e-mail address, logo, person, place, or event is intended or should be inferred. Microsoft, Microsoft Dynamics, the Microsoft Dynamics logo,.net Framework, Visual Studio, and Windows Azure are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners. 79