Create a Custom Authenticator
Version 5.1 by Thomas Mortagne on 2021/06/18
It is possible to plug to any existing authentication mechanism such as SiteMinder, etc.
To create a custom authentication do the following:
- Implement the XWikiAuthService interface. It's recommended to extends the XWikiAuthServiceImpl class which is a default implementation, this is very usefull if you want to reuse the standard login form for example).
- Edit the WEB-INF/xwiki.cfg file and add a xwiki.authentication.authclass property pointing to your class. For example:
xwiki.authentication.authclass = com.acme.MyCustomAuthenticationService
- XWiki 13.3+ To comply with latest best practices, your custom authentication should trigger a UserAuthenticatedEvent when it implement itself checkAuth(XWikiContext context) (if your authenticator is reusing the standard login form this part is handled by XWiki). You can find implementation examples in xwiki-platform-oldcore as MyFormAuthenticator and MyBasicAuthenticator. Note that a UserAuthenticatedEvent should be created with a UserReference.
Here is an example code for a custom authenticator designed as a component:
public class MyCustomAuthenticationService extends XWikiAuthServiceImpl
{
// We cannot use use "real" component injection here because authenticators are not component currently
// But it's recommended to put most of your authenticator actual code in a component and use this component,
// it will make a lot easier to reuse various XWiki tools and APIs
private MyCustomAuthentor authenticator;
// If you don't plan to reuse the standard XWiki login you should implement this method which is usually in charge or gathering the user credentials
// or other means of indicating what is the current user (HTTP headers, etc.)
@Override
public XWikiUser checkAuth(XWikiContext context)
{
// Call the actual authenticator
return this.authenticator.checkAuth(context);
}
// This is the method which will be called is you reuse the standard means of gathering of the credentials (login page, BASIC auth)
// What's left on your side if to validate the credential and create/update the XWiki user profile (and eventually synchronize other user related info like the groups, etc.)
@Override
public Principal authenticate(String username, String password, XWikiContext context) throws XWikiException
{
// Call the actual authenticator
return this.authenticator.checkAuth(context);
}
}
@Component(roles = MyCustomAuthenticator.class)
@Singleton
public MyCustomAuthenticator
{
@Inject
private ObservationManager observation;
public XWikiUser checkAuth(XWikiContext context)
{
// You authenticate a user somehow
...
// Since 13.3, if this is a new authentication (the user was not already authenticated in this session) you should send a notification about that
if (newAuth) {
// You have to retrieve its UserReference
// You should be able to use a UserReferenceResolver if needed
UserReference userReference = ...;
// Then, trigger a UserAuthenticatedEvent by passing previously retrieved user reference to UserAuthenticatedEvent constructor
this.observationManager.notify(new UserAuthenticatedEvent(userReference), null);
}
}
public Principal authenticate(String username, String password, XWikiContext context) throws XWikiException
{
...
}
}
{
// We cannot use use "real" component injection here because authenticators are not component currently
// But it's recommended to put most of your authenticator actual code in a component and use this component,
// it will make a lot easier to reuse various XWiki tools and APIs
private MyCustomAuthentor authenticator;
// If you don't plan to reuse the standard XWiki login you should implement this method which is usually in charge or gathering the user credentials
// or other means of indicating what is the current user (HTTP headers, etc.)
@Override
public XWikiUser checkAuth(XWikiContext context)
{
// Call the actual authenticator
return this.authenticator.checkAuth(context);
}
// This is the method which will be called is you reuse the standard means of gathering of the credentials (login page, BASIC auth)
// What's left on your side if to validate the credential and create/update the XWiki user profile (and eventually synchronize other user related info like the groups, etc.)
@Override
public Principal authenticate(String username, String password, XWikiContext context) throws XWikiException
{
// Call the actual authenticator
return this.authenticator.checkAuth(context);
}
}
@Component(roles = MyCustomAuthenticator.class)
@Singleton
public MyCustomAuthenticator
{
@Inject
private ObservationManager observation;
public XWikiUser checkAuth(XWikiContext context)
{
// You authenticate a user somehow
...
// Since 13.3, if this is a new authentication (the user was not already authenticated in this session) you should send a notification about that
if (newAuth) {
// You have to retrieve its UserReference
// You should be able to use a UserReferenceResolver if needed
UserReference userReference = ...;
// Then, trigger a UserAuthenticatedEvent by passing previously retrieved user reference to UserAuthenticatedEvent constructor
this.observationManager.notify(new UserAuthenticatedEvent(userReference), null);
}
}
public Principal authenticate(String username, String password, XWikiContext context) throws XWikiException
{
...
}
}
You can find various authenticators examples in extensions or sandbox.
Here's a tutorial on implementing a custom authentication class for authenticating against Oracle's SSO.