There is now a new .Net CAS Client which works in both mono and MS .Net. The key difference between this client and the existing ASP .Net clients are that this client allows you to proxy authenticate into non-browser based applications as well as browser based ones. For example, I may have a SOAP based Web service which I want to be able to proxy authenticate into. Such services are not intended to be directly accessed via the browser and so you can't simply redirect them via CAS if the user isn't logged in. Another example would be if you had a desktop application which you wanted to authenticate into via CAS - again you would have to use a proxy ticket and a browser based solution, such as an ASP .Net one, would be completely inappropriate.
The latest version of this client also allows authentication via a browser and can therefore take advantage of cookies set by CAS.
The client is available to download at ja-sig downloads. Simply include the dll in your .Net project as a reference.
The source code is available from SVN at ja-sig SVN.
Usage
Proxy Based Authentication
To continue the examples, imagine you have a web service which returns user details pulled from a database and keyed on a userid. You could have the web service take 2 parameters - a user name and a password - but that would mean that you would have to pass user credentials around. Hitting your web service via SSL would be an improvement, but still far from ideal. A better solution would be to take one parameter - a proxy ticket generated by CAS. You could then use this CAS client to get the user name in the following way:
...
using DotNetCASClient;
...
[WebMethod]
public String GetUserName(String ticket) {
//The first argument in the constructor is the service against which you trying to validate
//The second argument is the proxy validation URL for your CAS server
DotNetCASClientProxyValidate client
= new DotNetCASClientProxyValidate("http://myawesomeservice.uwe.ac.uk", "https://casserver.uwe.ac.uk/cas/proxyValidate");
String userid = client.Authenticate(ticket);
return userid;
}
...
Obviously, you would want to then use the username to retrieve details from the database and return them as well. If the authentication fails then the returned user will be 'failed'.
The DotNetCASClientProxyValidate class also has a GetCASXML method which also takes the ticket as a String. This performs the same authentication process that the Authenticate() method does but, instead of returning an user name, it returns the full XML that CAS returned - for example:
<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas"> <cas:authenticationSuccess> <cas:user>testUserName</cas:user> <cas:proxies> <cas:proxy>https://myawesomecasproxyplace/cas/pgtURL.asp</cas:proxy> </cas:proxies> </cas:authenticationSuccess> </cas:serviceResponse>
This particularly useful if you want to access more data than just the user name - especially if your CAS is configured to return other user information as well.
Browser Based Authentication
Browser based authentication only makes sense in the context of a web application - i.e. ASP.Net. In order to get browser based authentication working the first thing you have to do is add some properties to your Web.Config. These properties are:
- casLoginURL - The Login URL within your CAS server application. e.g. https://casserver.uwe.ac.uk/cas/login
- casValidateURL - The validation URL within your CAS server application. e.g. https://casserver.uwe.ac.uk/cas/serviceValidate (or proxyValidate if you want proxy tickets)
- serviceURL - The URL for the service you're trying to authenticate against. e.g. http://myawesomeservice.uwe.ac.uk/CASTestServiceValidation/Default.aspx
These should all be inside an ApplicationSettings element:
<configuration> <appSettings> <add key="casLoginURL" value="https://casserver.uwe.ac.uk/cas/login" /> <add key="casValidateURL" value="https://casserver.uwe.ac.uk/cas/serviceValidate" /> <add key="serviceURL" value="http://lmyawesomeservice.uwe.ac.uk/CASTestServiceValidation/Default.aspx" /> </appSettings> ... </configuration>
You then need to instantiate a new DotNetCASClientServiceValidate. Once you have an instance of DotNetCASClientServiceValidate, you can then call the Authenticate() method. This method takes three arguments: the request, the response and whether or not you need the XML from CAS - or just the user name. Be aware that Authenticate() will redirect the clients browser via CAS if required. IF the client has disabled redirects in their browser then this will not work.
This method will either return you a user name, or 'failed' or the XML returned from CAS.
Example Code:
protected void Page_Load(object sender, EventArgs e) { String userId = (String) Session["userId"]; if (userId == null) { DotNetCASClientServiceValidate client = new DotNetCASClientServiceValidate(); userId = client.Authenticate(Request, Response, true); lblCas.Text = "Had to authenticate via CAS..."; } Session["userId"] = userId; lblResult.Text = userId; }
Obviously, you'd want to do something more useful than simply display the user name on a page as in the above example!
It's also straightforward to take advantage of the built in ASP.Net authentication system with form based authentication. All that is required is a change in the Web.Config to configure a login form and a login ASP.Net page which uses the .Net CAS client as detailed above.
So, the change in the Web.Config might look something like:
<system.web>
<authorization>
<deny users="?" />
</authorization>
<authentication mode="Forms" >
<forms loginUrl="LoginPage.aspx" />
</authentication>
</system.web>
The authorization element specifies that any users who are not logged in should be forced to go via the login resource. The authentication element then defines the login process as form based using the form on LoginPage.aspx. This Login page need not contain any more than the following (although, of course, it can do):
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="LoginPage.aspx.cs" Inherits="LoginPage" %>
If we then look at the code in LoginPage.aspx.cs we can see how we can log in via CAS and then inform the .Net authnetication process that the login was succesful:
protected void Page_Load(object sender, EventArgs e) { DotNetCASClientServiceValidate client = new DotNetCASClientServiceValidate(); String userId = client.Authenticate(Request, Response, false); if (userId.Equals("failed")) { //Handle the auth failure... } else { FormsAuthentication.RedirectFromLoginPage(userId, false); } }
As you can see, we're basically just using the same process as above but, this time, using the RedirectFromLoginPage() method to declare the user to be logged in. This method takes two arguments: the username and a boolean specifying whether or not to set a permanent cookie.
This now mean that all resources in this web application are now protected by CAS. Any request to a page will ,if the user is unauthenticated, cause a redirect to LoginPage.aspx which will, in turn, take the user via CAS to log in.
Exception Handling
None of the methods in this client throw any exceptions. If an exception occurs during the authentication process then the class will log an error message and take appropriate action. The logs get logged to an event logger. On Windows systems this will get logged to the Application Event View under CasClient C#. According to the mono documentation, it will be logged to /var/lib/mono/eventlog on Unix systems, unless you specify a different path. (This may be a typo in the mono docs - it should perhaps be /var/log/...).
