Wednesday, January 28, 2009

UDDI SOA Howto

This article describes how to set up and configure and Windows Server 2003 UDDI Services.
UDDI Services are IIS hosted web services that require some kind of database.

So before installing UDDI Services you need to have IIS up and running.

Click on the screenshots to get a larger image.

1.) Add UDDI Server Component
Choose
Start - Settings - Control Panel - Add or Remove Programs - Add Remove Windows Compontents

2.) Pick UDDI Services



3.) Choose your Database

Choose the database component of your choice

If you do not have any SQL Server installed choose "Create a new MSDE database instance"
If you have SQL Server 2000 installed choose "Use the following SQL Server 2000 instance"
If you have SQL Server 2005 installed please follow this instruction before choosing "Use the following SQL Server 2000 instance" option



If you get the error message:
"This database instance does not meet the minimum version or Service Pack level requirements and cannot be used for installation. Please upgrade this instance or select another one."


it means you try to install UDDI Services on a server running SQL Server 2005 and you did not follow the instructions.

4.) SSL-encryption
If you have SSL configured for your IIS you can enable this option. If you do not have SSL enabled you can disable it here and enable it later when you SSL enabled your IIS.



5.) Choose setup location

Just choose the path where to install UDDI Services



6.) Choose the user

Choose the user UDDI Services will use



7.) Pick a name for your UDDI




8.) Disable "self register"
This is somehow related to publish the UDDI in Active Directory. I am not really sure what it does so disable it.


Great, we have UDDI Services up and running. Whats next?

Configuration of UDDI virtual directories access

1.) Open Computer Mangement snapin
Choose
Start - Settings - Control Panel - Administrative Tools - Computer Management

2.) Configure IIS "uddi" virtual directory to use Windows Authentication
in the computer management snap in go to
Internet Information Services - Web Sites - Default Web Site

Right click "uddi" and select Properties

Click on Directory Security, disable anonymous access and tick Integrated Windows authentication.

3.) Configure IIS "uddipublic" virtual directory to use UDDI Authentication
in the computer management snap in go to
Internet Information Services - Web Sites - Default Web Site

Right click "uddipublic" and select Properties

Click on Directory Security, enable anonymous access.


Great, we have configured UDDI Service authentication. Whats next?

Create Windows Publishing User account

In standard configuration every user in servers Administrators group has the right to publish Services.
But I really recommend creating a special user account for publishing UDDI service. That has the advantage you get all services published under one user, which gives you a much better overview over your running services.

In this case I created a User "UDDIAdmin" and added him to the "Administrators" group.

Now log in with your "UDDIAdmin" account, open Internet Explorer and type:

Publish a service on UDDI


http://localhost/uddi/

Now Click on Publish on you will see:



First thing we have to do is to create a provider. A "provider" is also referred as a "business" in UDDI terms. Basically the provider or business is just an embracing category for our services.

Create a Provider

Right click on provider and select "Add Provider". Then click on the new provider and edit the name to be "MyProvider".


Create a Service
Now right click on Provider and select "Add Service". Then click on the new service and edit the name to be "MyService".



Create a binding
Now right click on Service and select "Add Binding". Then click on the new binding and edit the URL to be the URL to your Service. "http://myserver/myservice.svc" in this case.


Create a tModel
Now right click on tModels and select "Add tModel". Then click on the new tModel and edit the name to be "MytModel".
What not really required but what makes it more UDDI is the following...
Click on the "Categories" tab and click on "Add Category". Now select "uddi-org:types" "Specification for a web service" "Specification for a web service described in WSDL" and click on "Add Category".
Now click on the "Overview Document" tab. Click on "Edit" and paste a link to the wsdl document of the service. e.g. http://myserver/myservice.svc?WSDL.

You could use these attributes later to pick the right tModel


Add instace Info
Now as a last step right click on your service select "Add instance info". Now type in "My" in the search box click on search and select "MytModel" from the list.

Done. We have published our first service in the UDDI.


Great, but what I do now with my UDDI?

A simple UDDI query in C#

You can install the Windows Server 2003 SDK or simply add a link to Microsoft.UDDI.dll in your C# project. Where to find those is described here.

Now implement the following code:

//URL to your UDDI directory
string uDDIURL = "http://myserver.com/uddi/";

// Take your tModel Key here. Look on the screenshots
string modelKey = "uuid:25f0c31f-1846-4f8c-919b-3164ffae3ed2";

// Take your service Key here. Look on the screenshots
string serviceKey= "49263d91-85e7-4285-b36c-a217d6a8e1b9";


// Create UDDI location object
UddiSiteLocation _siteLocation = new UddiSiteLocation(uDDIURL + "inquire.asmx",
uDDIURL + "publish.asmx",
uDDIURL + "extension.asmx",
string.Empty,
Microsoft.Uddi.AuthenticationMode.WindowsAuthentication);

// Initialize a new instance of the FindBinding class used to locate the service.
// Add the service key to the binding.
FindBinding _findBinding = new FindBinding(modelKey);
_findBinding.ServiceKey = serviceKey;

// Create the managed URL object. It is dynamically updated by the UDDI Registry
UddiConnection _connection = new UddiConnection(_siteLocation);
ManagedURL managedURL = new ManagedUrl(_connection, _findBinding);

if (managedURL.Count > 0)
Console.WriteLine("Hooray we did it");


Please keep in mind the managedURL object now keeps a steady connection with the UDDI and gets information on newly published or removed services. So there is absolutely no need to recreate the manageURL object in order to refresh it.

Further tips regardings UDDI Services can be found here.

For further examples please see this article on codeproject.com which includes some source code.

Tuesday, January 13, 2009

Dealing with Microsoft UDDI services

How do I install and setup Microsoft UDDI Services?

Read the UDDI SOA Howto.

Where to get the UDDI samples?


Microsoft did not include the UDDI samples in the current Windows SDK for Windows Server 2008 and .Net Framework 3.5.

Therefore you need to install the old Windows Server 2003 SDK .

After you installed the Core SDK you find the samples in

%PROGRAMFILES%\Microsoft SDK\samples\UDDI


Where to get Microsoft.UDDI.DLL?

You find it if you install the Windows Server 2003 SDK you find it in

%PROGRAMFILES%\Microsoft SDK\bin

or if you installed .NET 3.0 you find it in

%PROGRAMFILES%\Reference Assemblies\Microsoft\UDDI\v2.1\bin\system32


How to turn on Debugging?


If you want to turn on Debugging use regedit and goto:

[HKLM\SOFTWARE\Microsoft\UDDI\Debug]

set FileLogLevel to the appropriate value. Possible values are:

0 = None
1 = Error,
2 = Warning,
3 = FailAudit,
4 = PassAudit,
5 = Info ,
6 = Verbose

where 6 (Verbose) prints the most information into the file specified by LogFileName

How to configure another virtual directory for UDDI?

Open the IIS Manager, right click on Default Web Site and select New Virtual directory. Select a name for the alias, then select the UDDI/webroot folder (e.g. "c:\inet\uddi\webroot" ). Then select the Read, Run Scripts and Browse permission. After the wizard finishes right click on the virtual directoy and select Properties. Now change the Application Pool to "MSUDDIAppPool". Last thing is to select the ASP.NET tab and change the ASP.NET Version to 1.1.4322.

How to configure Authentication?

Microsoft UDDI offers basically 2 different types of authentication.

Windows Authentication and UDDIAuthentication. The difference is that in Windows Authentication you do not have to specify a Username and Password when you create the UDDIConnection object.

Windows Authentication
In Windows Authentication you do not have to specify a Username and Password. UDDI simply takes the Usercredentials received by the UDDI web service. To configure UDDI for using Windows credentials open the IIS Manager, right click the virtual directory (e.g. uddi or uddipublic), go to the Directory Security tab and click on Authentication and access control. Now make sure "Enable anonymous access" is disabled and Authenticated access is set to Integrated Windows authentication.

Ok, whats UDDIAuthentication?
When you use UDDIAuthentication you specify a Username and Password when you create the UDDIConnection object. However this user has to be a valid windows user account and has to have appropriate permissions. Using UDDIAuthentication the authentication of the account is not enforced by IIS but the UDDI Service will authenticate the user.
To configure UDDI for doing UDDI authentication open the IIS Manager, right click the virtual directory (e.g. uddi or uddipublic), go to the Directory Security tab and click on Authentication and access control. Now make sure "Enable anonymous access" is enabled.

Now use the following pattern:

UddiSiteLocation location = new UddiSiteLocation(
httpServerName + "inquire.asmx",
httpsServerName + "publish.asmx",
httpServerName + "extension.asmx",
"My Site",
AuthenticationMode.UddiAuthentication);

UddiConnection oConnect = new UddiConnection(location, @"Domain\Username", "Password");

oConnect.AutoGetAuthToken = true;

The secret to UDDI Authentication
1.) Try to the current user out the current HTTPContext (Windows Authentication)
2.) Query the Security.Authentication Mode Parameter which is set in the UDDI Database in table UDO_config.
3.) If the Security.Authentication Mode parameter is set to 8 UDDI tries Passport authentication.
4.) Windows Authentication is only used if the current user is not the anonymous user (Anonymous Access is disabled) and you did not specify a username in the connection.
5.) By Default UDDIAuthentication is used.


public AuthToken GetAuthToken(GetAuthToken gat)
{
Debug.Enter();
AuthToken token = new AuthToken();
try
{
IIdentity identity = HttpContext.Current.User.Identity;
int @int = Config.GetInt("Security.AuthenticationMode", 3);
if (8 == @int)
{
if (!(identity is PassportIdentity))
{
throw new UDDIException(ErrorType.E_fatalError, "UDDI_ERROR_PASSPORT_CONFIGURATION_ERROR");
}
Debug.Write(SeverityType.Info, CategoryType.Soap, "Generating credentials for Passport based authentication
dentity is " + gat.UserID);
PassportAuthenticator authenticator = new PassportAuthenticator();
if (!authenticator.GetAuthenticationInfo(gat.UserID, gat.Cred, out token.AuthInfo))
{
throw new UDDIException(ErrorType.E_unknownUser, "USER_FAILED_AUTHENTICATION");
}
if (!authenticator.Authenticate(token.AuthInfo, 0x3840))
{
throw new UDDIException(ErrorType.E_unknownUser, "UDDI_ERROR_USER_FAILED_AUTHENTICATION");
}
if (!Context.User.IsVerified)
{
throw new UDDIException(ErrorType.E_unknownUser, "UDDI_ERROR_NOT_A_VALID_PUBLISHER");
}
}
else if ((!((WindowsIdentity) identity).IsAnonymous && ((@int & 2) != 0)) && Utility.StringEmpty(gat.UserID))
{
Debug.Write(SeverityType.Info, CategoryType.Soap, "Generating credentials for Windows based authentication
Identity is " + identity.Name);
new WindowsAuthenticator().GetAuthenticationInfo(gat.UserID, gat.Cred, out token.AuthInfo);
}
else
{
if ((@int & 1) == 0)
{
throw new UDDIException(ErrorType.E_unsupported, "UDDI_ERROR_AUTHENTICATION_CONFIGURATION_ERROR");
}
Debug.Write(SeverityType.Info, CategoryType.Soap, "Generating credentials for UDDI based authentication");
new UDDIAuthenticator().GetAuthenticationInfo(gat.UserID, gat.Cred, out token.AuthInfo);
}
Debug.Write(SeverityType.Info, CategoryType.Soap, "Windows Identity is " + WindowsIdentity.GetCurrent().Name);
Debug.Write(SeverityType.Info, CategoryType.Soap, "Thread Identity is " + Thread.CurrentPrincipal.Identity.Name);
Debug.Write(SeverityType.Info, CategoryType.Soap, "HttpContext Identity is " + identity.Name);
Debug.Verify(Context.User.IsPublisher, "UDDI_ERROR_NO_PUBLISHER_CREDENTIALS", ErrorType.E_fatalError, new
bject[] { Context.User.ID });
Debug.Write(SeverityType.Info, CategoryType.Authorization, "Authenticated user (userid = " + gat.UserID + " )");
}
catch (Exception exception)
{
DispositionReport.Throw(exception);
}
return token;
}


Errors and Solutions

If authentication fails with "Authetication failed" and in the UDDI log you will see.

FAIL AUTH 2009/01/13 18:09:14 System.ArgumentOutOfRangeException: Length cannot be less than zero.
Parameter name: length
at System.String.Substring(Int32 startIndex, Int32 length)
at UDDI.API.Authentication.UDDIAuthenticator.GetAuthenticationInfo(String userid, String password, String& ticket)

Dont forget to put an @ before the string specifying the username so use:

string szUsername = @"Domain\User";

Monday, January 12, 2009

How to get rid of http://tempuri.org/ in WCF WSDL

"Each XML Web Service needs a unique namespace in order for client applications to distinguish it from other services on the Web. By default, ASP.Net Web Services use http://tempuri.org/ for this purpose. While this suitable for XML Web Services under development, published services should use a unique, permanent namespace." (http://tempuri.org)

By default WCF maps all service operations to the targetnamespace http://tempuri.org/ .
The problem with this approach occurs as soon as you as you need to uniquely indentify a service operation and you have more than just one service. e.g. in Biztalk or Microsoft Managed Service Engine.
Guess you have a 2 services both with the DoSomeThing() function. As both use the http://tempuri.org namespace for their operations, you can't uniquely indentify them.

To get rid of http://tempuri.org/ in your WSDL in WCF do the following:

1.) In your ServiceContract attribute constructor define the Namespace property.

[ServiceContract(Namespace = "http://myservice.com")]

public interface IMyService

2.) For your ServiceClass create the ServiceBehavior attribute with Namespace property

[ServiceBehavior(Namespace = "http://myservice.com")]

class MyService : IMyService

3.) In all your bindings set the bindingNamespace property

<endpoint binding="basicHttpBinding" bindingNamespace="http://myservice.com"....