Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Unauthorized requests to plugin xapi endpoint

42 views
Skip to first unread message

Daniel

unread,
Jan 27, 2025, 9:18:24 PMJan 27
to xnat_discussion
Hello,

I have a plugin that defines a xapi endpoint (e.g. localhost:8080/xnat/xapi/test) to retrieve some information from another platform. Also, I'm using the openid plugin for auth in XNAT (the other platform uses the same method). 

The main idea is that the user logins with openid to the external platform, and then this platform sends API requests to the plugin xapi endpoint (which will include the Authorization Bearer token) to retrieve some info.

So, what I want to do is:
1) Send GET request to the API endpoint, with Authorization Bearer header containing the oidc token
2) In the API, process the request, extract the token and get the user related to that token (through naming pattern with sub). I believe this can be done with Users.getUserManagementService().getUser(userIdentifier) from org.nrg.xdat.security.helpers.Users
3) Use the extracted user for further processing and information extraction

Actually, the step about retrieving the user is optional I think, I just want to validate the authorization with the token and not a signed-in xnat user (i.e. JSESSIONID or similar).

I have implemented this functionality in the plugin. However, I'm finding that the xapi is protected by XNAT user auth as I get a HTTP 401 Unauthorized. The only way I have found to get through is by:

1) Using Authorization Basic header with username:password encoded in base64. This is not suitable for my case since we're using openid (and for security concerns).
2) Use an Alias Token, but I would like a more straightforward process that doesn't involve the user copy-pasting the token into the platform sending the API requests and having to refresh this every time it expires.

Is there any way to disable the XNAT user auth from this specific xapi endpoint so that authorization can be done through a oidc token?

Sorry for the long post.

John Flavin

unread,
Jan 28, 2025, 5:47:46 PMJan 28
to xnat_di...@googlegroups.com
I'm surprised that it is giving you a 401. Did you implement your API with an @XapiRequestMapping annotation? And if so, what did you use for the restrictTo param, if anything?

Others would probably have more knowledge about this than I have, and hopefully will correct me if this is wrong, but I thought that an XAPI method would by default be open if not explicitly restricted to some user/role/access level/etc.

John Flavin

--
You received this message because you are subscribed to the Google Groups "xnat_discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to xnat_discussi...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/xnat_discussion/f0b1099b-5f8a-4095-bb12-32ecf5faa2d0n%40googlegroups.com.

Daniel

unread,
Jan 28, 2025, 6:17:39 PMJan 28
to xnat_discussion
Thanks for the response John.

You're right that I wasn't using XapiRequestMapping. Since I'm leveraging an already-created plugin instead of a new one, I didn't notice that some API endpoints (exactly the ones that I'm working with) have a custom RequestMapping that apparently has a default restrictTo level to AccessLevel.Read. I'll try modifying that and I guess it should work then.

Thank you again.

Rick Herrick

unread,
Jan 28, 2025, 6:29:58 PMJan 28
to xnat_di...@googlegroups.com
Actually the default access level for endpoints annotated with @XapiRequestMapping is sort of open, but not completely open: if your XNAT is an open XNAT (i.e. doesn't require authentication to access publicly available projects and data), then it is open, but on a standard XNAT you must at least be authenticated to access the endpoint. This is due to XNAT's security filter, which will reject the request without a valid authentication object before it ever gets to the point of checking the access level of the endpoint.

To make your endpoint truly open, so that the external service can access it without creating a session, you need to add the URL starting with /xapi/... to the openUrls attribute of the @XnatPlugin annotation, something like:

@XnatPlugin(value = "DanielsPlugin", name = "Daniel's Plugin", openUrls = "/xapi/test")

Within your method, you'll want to validate the payload delivered and throw a 403 as appropriate if the user is invalid or whatever, i.e. you'll be doing your own authentication in that method. But adding that endpoint as an open URL tells the security filter that it can allow that call through.

Daniel

unread,
Jan 28, 2025, 6:36:38 PMJan 28
to xnat_discussion
Thanks for the response Rick, that is truly helpful. I'll try all these and report back if I encounter more problems. Thank you.

Daniel

unread,
Jan 29, 2025, 7:30:07 AMJan 29
to xnat_discussion
Hello all,

I'm still getting a 401 even though I set restrictTo to AccessLevel.Null and specify the API endpoint in the openUrls' plugin configuration. I tried creating a new plugin from the xnat-template-plugin to test if maybe the already-creating plugin was the issue. However, the same is happening. The API code is the following:
@Api("Template API")
@XapiRestController
@RequestMapping(value = "/template_test")
@Slf4j
public class TemplateApi extends AbstractXapiRestController {
    @Autowired
    protected TemplateApi(final UserManagementServiceI userManagementService, final RoleHolder roleHolder, final TemplateService templateService) {
        super(userManagementService, roleHolder);
        _templateService = templateService;
    }

    @ApiOperation(value = "Test endpoint", notes = "Test endpoint", response = Template.class)
    @ApiResponses({@ApiResponse(code = 200, message = "Template successfully retrieved."),
                   @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
                   @ApiResponse(code = 500, message = "Unexpected error")})
    @XapiRequestMapping(value = "/test",produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = AccessLevel.Null)
    public String testEntity() {
        return "Hello World";
    }

And the XnatPlugin:
@XnatPlugin(value = "templatePlugin", name = "XNAT Template Plugin",
            entityPackages = "org.nrg.xnat.plugins.template.entities",
            openUrls = {"/xapi/template_test/test"},
            dataModels = {@XnatDataModel(value = TemplateSampleBean.SCHEMA_ELEMENT_NAME,
                                         singular = "Template",
                                         plural = "Templates",
                                         code = "TM")})

A GET request to http://localhost:8080/xnat/xapi/template_test/test returns 401 Unauthorized.

I do have to mention that the XNAT platform requires user login. The API endpoint works perfectly (i.e. returns "Hello World") if I uncheck it or if I pass the Authorization Basic/Alias Token in the request headers, but those options don't work for my case.

Rick Herrick

unread,
Jan 29, 2025, 11:08:15 AMJan 29
to xnat_di...@googlegroups.com
Sorry, I forgot a step!
  1. Log into XNAT as an administrator
  2. Click on Administer->Site Administration
  3. Under Site Settings, click Installed Plugins
  4. Look in the panel entitled Open URLs Defined in Plugins: your URL should be in there
  5. Click the switch for that URL so that it says Available
  6. Click Save
  7. Try again

Daniel

unread,
Jan 29, 2025, 2:31:56 PMJan 29
to xnat_discussion
That was it! Now it looks like it works perfectly. Thanks a lot, Rick.
Reply all
Reply to author
Forward
0 new messages