Security Integration - External Components

Discovering OAuth 2.0 configuration for external integrations

ModelOp Center has a mechanism that allows external integrations to dynamically retrieve their OAuth 2.0 configurations. This mechanism is available at:

<ModelOp Center URL>/api/oauth2/.well-known-configuration

Sample global response:

{ "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 }

If a given external integration needs to fetch its specific configurations, then it can perform a request and append its well-known name. The response will contain any existing configurations related to the specified name.

Well-known name refers to a simple identifier for an external integration, typically its short form name. This provides a permanent relative URI that can be hardcoded into artifacts so they can configure themselves at runtime.

Sample request for Jupyter

<ModelOp Center URL>/api/oauth2/.well-known-configuration/jupyter

If existing configurations are found, then a response similar to the following will be returned:

{ "clientId": "my_jupyter_client", "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 } }

Additional security considerations

  • Access groups specified under the group claim name, contained in an access/id token, will be saved as GrantedAuthorities with prefix GROUP_ .

  • System clients will be assigned a role of ROLE_SYSTEM.

  • Admin users will be assigned a role of ROLE_ADMIN.


External Jupyter Notebook

Distinguishing between browser and non-browser requests

With OAuth 2.0 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)));