Authentication and Authorization Using the OSP

Authentication and Authorization

As I mentioned in my last post, Using the OSP to Get the Current User’s Name, the Oncology System Platform (OSP) provides many services. In this post, I’ll show you how to use the OSP to authenticate a user. I’ll also show you how to authorize a user based on his or her group.

To be clear, there’s a difference between authentication and authorization. Authentication is the process of verifying a user’s identity. Typically, this is done via a username and password. Authorization is the process of determining whether an authenticated user is allowed to perform a certain action.

In most cases, you won’t have to worry about authentication because the Eclipse Scripting API does this for you automatically. For example, in a stand-alone app, creating the Application object automatically asks the user for his or her credentials.

The reason you may want to authenticate a user yourself is when you want to verify the user’s identity when performing a sensitive action (e.g., signing off an important document). In addition, you may want to check that the user belongs to a specific group (e.g., oncologist) before allowing him or her to perform the action.

Authentication

Let’s start with authentication. The API for the OSP includes an “Authenticate” method that will do most of the work for us. Here’s its declaration:

It takes as input the user ID, the user’s password, and your application’s name. It returns two objects: the return code as an “out” parameter and the authenticated user information.

The return code is an enum that specifies the result of the authentication, like whether the user was authenticated or if some error occurred. The user information (IUserInfo interface) contains the user ID, the user’s name, the user’s group ID, and other information.

Instead of using this method directly, we’re going to wrap it in a class of our own. We’ll do this to keep our program independent of the technology used for authentication. Furthermore, we’ll create an interface for our class, so that whatever module is using it doesn’t even need to reference the OSP API. This architecture completely separates our program from the OSP.

Here are the two interfaces we’ll use:

The IAuthentication interface has a single method: Authenticate. It takes the user ID and password, and it returns an IAuthenticatedUser object. The idea is that if the return value is not null, the authentication was successful. If the return value is null, however, it means the user wasn’t authenticated.

The IAuthenticatedUser has just one property: the group ID of the user. We’ll use this property later when we need to authorize the user. You could add more properties to this interface if they’ll be used by your program.

Now let’s look at their implementation. I’ve put the following classes in their own class library. This library needs to reference the following assemblies: VMS.OSP.ICommon.dll, VMS.OSP.Common.dll, VMS.OSP.IServices.dll, and VMS.OSP.Services.dll. On my computer, these are located in C:\Windows\Microsoft.NET\assembly\GAC_MSIL, under the directory with the same name as the assembly.

The constructor of the Authentication class takes your application name, which will be passed to the Authenticate method of the OSP. (I’m not entirely sure why the OSP needs your application’s name—probably to log it somewhere.)

Our Authenticate method creates the necessary OSP objects, and then calls the OSP’s Authenticate method we saw earlier. If the return code is OK, we return an AuthenticatedUser object with the group ID. Otherwise, we return null. We’ve wrapped all this code in a try/catch statement in case something goes wrong.

Authorization

Let’s begin with the interfaces.

In the IAuthorization interface, we have two methods: one for authorizing an oncologist and another for authorizing a physicist. You can add more methods, depending on the groups for which you’d like to authorize.

These methods return an IAuthorizedUser object. If it’s not null, the user is authorized; otherwise, the user is not authorized. This interface doesn’t contain anything—it’s simply used as a way to indicate that the user was authorized.

The following are the implementations. I’ve put these in the same class library as the authentication implementation.

The constructor of the Authorization class takes the group IDs for each of the groups we’re interested in. The reason we don’t hard-code these as constants is that we may want to put these IDs in the application’s configuration file.

The methods are straightforward: check whether the user’s group ID matches the appropriate ID. The group ID is obtained from an IAuthenticatedUser, so we know the user’s identity has been verified.

Final Thoughts

Now that we’ve wrapped the authentication and authorization functionality in interfaces and classes, we can use them as needed. I recommend using the interfaces wherever possible by passing them to the classes that need them (see dependency injection).

Ideally, the implementation classes will be instantiated only once, somewhere at the start of your program (e.g., App.xaml.cs in a stand-alone app). Only that project will need to reference the OSP library, while all other projects will simply reference your authentication/authorization interface library.

Finally, here’s an implementation note. In the IAuthorization interface, the authorize methods take an IAuthenticatedUser, which means that the user must have been authenticated previously. Alternatively, we could assume that the current user has already been authenticated, given that he or she logged in through Eclipse. In that case, we could change our authorize methods to simply take a user ID. We would then need to use the OSP to look up the user’s group ID and then determine whether it matches with the desired group ID.

2 thoughts on “Authentication and Authorization Using the OSP

Leave a Reply

Your email address will not be published. Required fields are marked *