| 
									
										
										
										
											2021-08-20 10:58:07 -07:00
										 |  |  | package controllers;
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 13:36:47 -05:00
										 |  |  | import auth.CookieConfigs;
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  | import auth.sso.SsoManager;
 | 
					
						
							|  |  |  | import auth.sso.SsoProvider;
 | 
					
						
							|  |  |  | import auth.sso.oidc.OidcCallbackLogic;
 | 
					
						
							| 
									
										
										
										
											2021-11-22 16:33:14 -08:00
										 |  |  | import client.AuthServiceClient;
 | 
					
						
							|  |  |  | import com.datahub.authentication.Authentication;
 | 
					
						
							| 
									
										
										
										
											2023-09-21 22:00:14 -05:00
										 |  |  | import com.linkedin.entity.client.SystemEntityClient;
 | 
					
						
							| 
									
										
										
										
											2022-08-23 09:54:34 -07:00
										 |  |  | import java.net.URLEncoder;
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  | import java.nio.charset.StandardCharsets;
 | 
					
						
							| 
									
										
										
										
											2023-12-26 14:34:10 -06:00
										 |  |  | import java.util.ArrayList;
 | 
					
						
							|  |  |  | import java.util.List;
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  | import java.util.concurrent.CompletableFuture;
 | 
					
						
							|  |  |  | import java.util.concurrent.CompletionStage;
 | 
					
						
							| 
									
										
										
										
											2021-11-22 16:33:14 -08:00
										 |  |  | import javax.annotation.Nonnull;
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  | import javax.inject.Inject;
 | 
					
						
							| 
									
										
										
										
											2024-04-16 10:12:48 -05:00
										 |  |  | import javax.inject.Named;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import io.datahubproject.metadata.context.OperationContext;
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  | import lombok.extern.slf4j.Slf4j;
 | 
					
						
							| 
									
										
										
										
											2023-12-26 14:34:10 -06:00
										 |  |  | import org.pac4j.core.client.Client;
 | 
					
						
							|  |  |  | import org.pac4j.core.client.Clients;
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  | import org.pac4j.core.config.Config;
 | 
					
						
							|  |  |  | import org.pac4j.core.engine.CallbackLogic;
 | 
					
						
							|  |  |  | import org.pac4j.core.http.adapter.HttpActionAdapter;
 | 
					
						
							|  |  |  | import org.pac4j.play.CallbackController;
 | 
					
						
							|  |  |  | import org.pac4j.play.PlayWebContext;
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  | import play.mvc.Http;
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  | import play.mvc.Result;
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  | import play.mvc.Results;
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * A dedicated Controller for handling redirects to DataHub by 3rd-party Identity Providers after
 | 
					
						
							|  |  |  |  * off-platform authentication.
 | 
					
						
							|  |  |  |  *
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  |  * <p>Handles a single "callback/{protocol}" route, where the protocol (ie. OIDC / SAML) determines
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |  * the handling logic to invoke.
 | 
					
						
							|  |  |  |  */
 | 
					
						
							|  |  |  | @Slf4j
 | 
					
						
							|  |  |  | public class SsoCallbackController extends CallbackController {
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-22 16:33:14 -08:00
										 |  |  |   private final SsoManager _ssoManager;
 | 
					
						
							| 
									
										
										
										
											2023-12-26 14:34:10 -06:00
										 |  |  |   private final Config _config;
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @Inject
 | 
					
						
							| 
									
										
										
										
											2021-11-22 16:33:14 -08:00
										 |  |  |   public SsoCallbackController(
 | 
					
						
							|  |  |  |       @Nonnull SsoManager ssoManager,
 | 
					
						
							| 
									
										
										
										
											2024-04-16 10:12:48 -05:00
										 |  |  |       @Named("systemOperationContext") @Nonnull OperationContext systemOperationContext,
 | 
					
						
							| 
									
										
										
										
											2023-09-21 22:00:14 -05:00
										 |  |  |       @Nonnull SystemEntityClient entityClient,
 | 
					
						
							| 
									
										
										
										
											2023-02-14 13:36:47 -05:00
										 |  |  |       @Nonnull AuthServiceClient authClient,
 | 
					
						
							| 
									
										
										
										
											2023-12-26 14:34:10 -06:00
										 |  |  |       @Nonnull Config config,
 | 
					
						
							| 
									
										
										
										
											2023-02-14 13:36:47 -05:00
										 |  |  |       @Nonnull com.typesafe.config.Config configs) {
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |     _ssoManager = ssoManager;
 | 
					
						
							| 
									
										
										
										
											2023-12-26 14:34:10 -06:00
										 |  |  |     _config = config;
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |     setDefaultUrl("/"); // By default, redirects to Home Page on log in.
 | 
					
						
							| 
									
										
										
										
											2022-10-21 10:58:27 -07:00
										 |  |  |     setSaveInSession(false);
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  |     setCallbackLogic(
 | 
					
						
							|  |  |  |         new SsoCallbackLogic(
 | 
					
						
							|  |  |  |             ssoManager,
 | 
					
						
							| 
									
										
										
										
											2024-04-16 10:12:48 -05:00
										 |  |  |                 systemOperationContext,
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  |             entityClient,
 | 
					
						
							|  |  |  |             authClient,
 | 
					
						
							|  |  |  |             new CookieConfigs(configs)));
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |   public CompletionStage<Result> handleCallback(String protocol, Http.Request request) {
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |     if (shouldHandleCallback(protocol)) {
 | 
					
						
							|  |  |  |       log.debug(String.format("Handling SSO callback. Protocol: %s", protocol));
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  |       return callback(request)
 | 
					
						
							|  |  |  |           .handle(
 | 
					
						
							|  |  |  |               (res, e) -> {
 | 
					
						
							|  |  |  |                 if (e != null) {
 | 
					
						
							|  |  |  |                   log.error(
 | 
					
						
							|  |  |  |                       "Caught exception while attempting to handle SSO callback! It's likely that SSO integration is mis-configured.",
 | 
					
						
							|  |  |  |                       e);
 | 
					
						
							|  |  |  |                   return Results.redirect(
 | 
					
						
							|  |  |  |                           String.format(
 | 
					
						
							|  |  |  |                               "/login?error_msg=%s",
 | 
					
						
							|  |  |  |                               URLEncoder.encode(
 | 
					
						
							|  |  |  |                                   "Failed to sign in using Single Sign-On provider. Please try again, or contact your DataHub Administrator.",
 | 
					
						
							|  |  |  |                                   StandardCharsets.UTF_8)))
 | 
					
						
							|  |  |  |                       .discardingCookie("actor")
 | 
					
						
							|  |  |  |                       .withNewSession();
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |                 return res;
 | 
					
						
							|  |  |  |               });
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  |     return CompletableFuture.completedFuture(
 | 
					
						
							|  |  |  |         Results.internalServerError(
 | 
					
						
							|  |  |  |             String.format(
 | 
					
						
							|  |  |  |                 "Failed to perform SSO callback. SSO is not enabled for protocol: %s", protocol)));
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  |   /** Logic responsible for delegating to protocol-specific callback logic. */
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |   public class SsoCallbackLogic implements CallbackLogic<Result, PlayWebContext> {
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private final OidcCallbackLogic _oidcCallbackLogic;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  |     SsoCallbackLogic(
 | 
					
						
							|  |  |  |         final SsoManager ssoManager,
 | 
					
						
							| 
									
										
										
										
											2024-04-16 10:12:48 -05:00
										 |  |  |         final OperationContext systemOperationContext,
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  |         final SystemEntityClient entityClient,
 | 
					
						
							|  |  |  |         final AuthServiceClient authClient,
 | 
					
						
							|  |  |  |         final CookieConfigs cookieConfigs) {
 | 
					
						
							|  |  |  |       _oidcCallbackLogic =
 | 
					
						
							|  |  |  |           new OidcCallbackLogic(
 | 
					
						
							| 
									
										
										
										
											2024-04-16 10:12:48 -05:00
										 |  |  |               ssoManager, systemOperationContext, entityClient, authClient, cookieConfigs);
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Override
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  |     public Result perform(
 | 
					
						
							|  |  |  |         PlayWebContext context,
 | 
					
						
							|  |  |  |         Config config,
 | 
					
						
							|  |  |  |         HttpActionAdapter<Result, PlayWebContext> httpActionAdapter,
 | 
					
						
							|  |  |  |         String defaultUrl,
 | 
					
						
							|  |  |  |         Boolean saveInSession,
 | 
					
						
							|  |  |  |         Boolean multiProfile,
 | 
					
						
							|  |  |  |         Boolean renewSession,
 | 
					
						
							|  |  |  |         String defaultClient) {
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |       if (SsoProvider.SsoProtocol.OIDC.equals(_ssoManager.getSsoProvider().protocol())) {
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  |         return _oidcCallbackLogic.perform(
 | 
					
						
							|  |  |  |             context,
 | 
					
						
							|  |  |  |             config,
 | 
					
						
							|  |  |  |             httpActionAdapter,
 | 
					
						
							|  |  |  |             defaultUrl,
 | 
					
						
							|  |  |  |             saveInSession,
 | 
					
						
							|  |  |  |             multiProfile,
 | 
					
						
							|  |  |  |             renewSession,
 | 
					
						
							|  |  |  |             defaultClient);
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |       }
 | 
					
						
							|  |  |  |       // Should never occur.
 | 
					
						
							| 
									
										
										
										
											2023-12-06 11:02:42 +05:30
										 |  |  |       throw new UnsupportedOperationException(
 | 
					
						
							|  |  |  |           "Failed to find matching SSO Provider. Only one supported is OIDC.");
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private boolean shouldHandleCallback(final String protocol) {
 | 
					
						
							| 
									
										
										
										
											2023-12-26 14:34:10 -06:00
										 |  |  |     if (!_ssoManager.isSsoEnabled()) {
 | 
					
						
							|  |  |  |       return false;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     updateConfig();
 | 
					
						
							|  |  |  |     return _ssoManager.getSsoProvider().protocol().getCommonName().equals(protocol);
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private void updateConfig() {
 | 
					
						
							|  |  |  |     final Clients clients = new Clients();
 | 
					
						
							|  |  |  |     final List<Client> clientList = new ArrayList<>();
 | 
					
						
							|  |  |  |     clientList.add(_ssoManager.getSsoProvider().client());
 | 
					
						
							|  |  |  |     clients.setClients(clientList);
 | 
					
						
							|  |  |  |     _config.setClients(clients);
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |   }
 | 
					
						
							|  |  |  | }
 |