Extend JIRA Authentication
Steps
JIRA 11.0.0+
The authentication schemes offered when an administrator defines a JIRA instance are pluggable: the extension ships "No authentication" and "Basic auth", and a new scheme adds itself to that list. A scheme has two halves that are tied together by a single identifier: a user interface extension contributing the fields the administrator fills, and a Java Component signing the requests with them. The Basic authentication scheme is the working example to copy, its user interface under JIRA.JIRAAuth and its Component at BasicAuthJIRAAuthenticatorFactory.
- Choose the identifier of your scheme, which will tie its two halves together, for example oauth.
- Create a page holding an XWiki.UIExtensionClass xobject whose "Extension Point ID" is org.xwiki.contrib.jira.authconfig, whose "Extension Scope" is wiki, and whose name is unique among the schemes.
- Set the three parameters of that user interface extension.
Parameter Value config_id The identifier you chose. translation_key The translation key of the name shown in the "Authentication type" field. config_displayer_reference The reference of the page displaying your scheme's own fields under "Authentication system configuration". - Create the page named by config_displayer_reference, displaying one form field per piece of information your scheme needs, and an XClass to store them keyed by the instance id.
- Add the translation of translation_key to a translation bundle of your extension.
- Write a Java Component implementing org.xwiki.contrib.jira.config.JIRAAuthenticatorFactory, annotated @Named with the identifier you chose, whose get(String serverId) method reads the stored configuration of that instance and returns a JIRAAuthenticator, or throws JIRAAuthenticatorException when it cannot.
- Implement the four methods of org.xwiki.contrib.jira.config.JIRAAuthenticator.
Method Returns getRestClientAuthenticationHandler() The AuthenticationHandler the JIRA Scripting API passes to Atlassian's client. authenticateInHttpClient(context, request, targetHost) Nothing; it signs the HttpClient request the Macros use, for instance by adding a header. isAuthenticatingRequest() Whether requests really are authenticated, which lets callers tell a configured scheme from an inert one. getId() A value identifying this authentication, used to build the cache key of asynchronous Macro rendering. Make it differ whenever the resulting rights differ. - Install your extension, then select your scheme in the "Authentication type" field of a JIRA instance definition. Its fields appear, and issues are returned through it.
FAQ
Why must the Component hint equal the config_id?
Because that identifier is how the stored configuration of an instance is matched with the factory able to read it; a mismatch leaves the scheme selectable but never applied.
Can the scheme be written entirely in wiki pages?
No. The user interface half is wiki pages, but JIRAAuthenticatorFactory and JIRAAuthenticator are Java interfaces not exposed to scripts, so the Component half needs a JAR.
Where are the credentials of my scheme stored?
Wherever your displayer page stores them, which for Basic authentication is an xobject per instance id on a dedicated configuration page of the wiki.
Why does asynchronous rendering show me another user's issues?
Because getId() returns the same value for authentications granting different rights, so the cached rendering is shared. Make it depend on the identity being used.