External Jupyter Notebook
Distinguishing between browser and non-browser requests
With OAuth2 enabled, when an unauthenticated user tries to access or perform an action against ModelOp Center using an external Jupyter notebook, they will not be allowed to do so until they authenticate. The trigger for the authentication logic, located in the jupyter-plugin repository, is a 401 Unauthorized
status code. However, Spring Security configured as OAuth2Login is no longer sending a 401 Unauthorized
, but instead a 302 Found
status code. To override the 302 Found
status code, we introduced the CustomAuthenticationEntryPoint
class. The purpose of this class is to inspect all requests for protected resources coming from an unauthenticated user, and to determine if a 302 Found
or 401 Unauthorized
status code should be returned.
We identify external Jupyter notebook requests (non-browser requests) by checking for the Accept
header and its value. If a request is coming from an external Jupyter notebook (non-browser request), then the Accept
header will not contain the text/html
value, in which case we return 401 Unauthorized
. Otherwise, we return 302 Found
and redirect to the login page.
To enable the use of CustomAuthenticationEntryPoint
class, include the following line in the odg-gateway-service repository SecurityConfig class:
http.exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint(URI.create(this.authenticationFailureRedirectUri)));
Accessing OAuth2 configuration
In order to retrieve the OAuth2 configuration information, a new endpoint was introduced: /api/oauth2/.well-known-configuration
. This endpoint is used by all ModelOp OAuth2 clients to retrieve generic and client specific information such as authorization URI, client id, response type, scope, and redirect.
{ "name": "modelop", "issuerUri": "https://authorization.server", "authorizationUri": "https://authorization.server/as/authorization.oauth2", "tokenUri": "https://authorization.server/as/token.oauth2", "userInfoUri": "https://authorization.server/idp/userinfo.openid", "userNameAttribute": "sub", "jwkSetUri": "https://iauthorization.server/pf/JWKS", "introspectionUri": null }
For example, to retrieve common OAuth2 configuration, execute a GET request to /api/oauth2/.well-known-configuration
. To retrieve Jupyter client specific information, execute a GET request to /api/oauth2/.well-known-configuration/jupyter
where jupyter
is the OAuth2 client id.
{ "clientId": "jupyter", "scopes": [ "openid", "profile", "email" ], "redirectUri": "http://modelop.center/jupyter.html", "responseType": "token", "oAuth2Provider": { "name": "modelop", "issuerUri": "https://authorization.server", "authorizationUri": "https://authorization.server/as/authorization.oauth2", "tokenUri": "https://authorization.server/as/token.oauth2", "userInfoUri": "https://authorization.server/idp/userinfo.openid", "userNameAttribute": "sub", "jwkSetUri": "https://authorization.server/pf/JWKS", "introspectionUri": null } }