Create a Custom Authenticator
Version 7.1 by Thomas Mortagne on 2021/06/18
It is possible to plug to any existing authentication mechanism by providing a bridge for it.
To create a custom authentication do the following:
- Implement the XWikiAuthService interface. It's recommended to extends the XWikiAuthServiceImpl class which is the 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
Here is an example code for a custom authenticator:
public class MyCustomAuthenticationService extends XWikiAuthServiceImpl
{
// We cannot use use "real" component injection here because authenticators are not components currently
// But it's recommended to put most of your authenticator actual code in a component (or several components) 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 if 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 components currently
// But it's recommended to put most of your authenticator actual code in a component (or several components) 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 if 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.