public async Task <Response> ExecuteAsync(NancyContext context, IResponseFormatter response) { if (ConfigurationStore.GetIsEnabled() == false) { log.Warn($"{ConfigurationStore.ConfigurationSettingsName} user authentication API was called while the provider was disabled."); return(ResponseCreator.BadRequest(new string[] { "This authentication provider is disabled." })); } var model = modelBinder.Bind <LoginRedirectLinkRequestModel>(context); var state = model.RedirectAfterLoginTo; if (string.IsNullOrWhiteSpace(state)) { state = "/"; } var whitelist = webPortalConfigurationStore.GetTrustedRedirectUrls(); if (!Requests.IsLocalUrl(state, whitelist)) { log.WarnFormat("Prevented potential Open Redirection attack on an authentication request, to the non-local url {0}", state); return(ResponseCreator.BadRequest("Request not allowed, due to potential Open Redirection attack")); } var nonce = Nonce.GenerateUrlSafeNonce(); try { var issuer = ConfigurationStore.GetIssuer(); var issuerConfig = await identityProviderConfigDiscoverer.GetConfigurationAsync(issuer); var url = urlBuilder.Build(model.ApiAbsUrl, issuerConfig, nonce, state); return(ResponseCreator.AsOctopusJson(response, new LoginRedirectLinkResponseModel { ExternalAuthenticationUrl = url }) .WithCookie(new NancyCookie("s", State.Protect(state), true, false, DateTime.UtcNow.AddMinutes(20))) .WithCookie(new NancyCookie("n", Nonce.Protect(nonce), true, false, DateTime.UtcNow.AddMinutes(20)))); } catch (Exception ex) { log.Error(ex); return(response.AsRedirect($"{state}?error=Login failed. Please see the Octopus Server logs for more details.")); } }