mirror of
https://github.com/gravitational/teleport.git
synced 2026-11-02 14:59:53 +08:00
Add private key policy enforcement. - Add private key policy cert extensions and enforcement. - Add private key policy settings and attestation logic. - Wire attestation request through login endpoints. - Store attestation data for reissue requests. - Add private key policy discovery and logic. - Relogin on hardware key policy errors. - Include integration with Teleport Connect.
171 lines
5.5 KiB
Go
171 lines
5.5 KiB
Go
/*
|
|
Copyright 2015-2019 Gravitational, Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package web
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/gravitational/teleport/api/types"
|
|
"github.com/gravitational/teleport/lib/auth"
|
|
|
|
"github.com/gravitational/teleport/lib/client"
|
|
"github.com/gravitational/teleport/lib/httplib"
|
|
|
|
"github.com/gravitational/form"
|
|
"github.com/gravitational/trace"
|
|
"github.com/julienschmidt/httprouter"
|
|
)
|
|
|
|
func (h *Handler) samlSSO(w http.ResponseWriter, r *http.Request, p httprouter.Params) string {
|
|
logger := h.log.WithField("auth", "saml")
|
|
logger.Debug("Web login start.")
|
|
|
|
req, err := parseSSORequestParams(r)
|
|
if err != nil {
|
|
logger.WithError(err).Error("Failed to extract SSO parameters from request.")
|
|
return client.LoginFailedRedirectURL
|
|
}
|
|
|
|
response, err := h.cfg.ProxyClient.CreateSAMLAuthRequest(r.Context(), types.SAMLAuthRequest{
|
|
ConnectorID: req.connectorID,
|
|
CSRFToken: req.csrfToken,
|
|
CreateWebSession: true,
|
|
ClientRedirectURL: req.clientRedirectURL,
|
|
})
|
|
if err != nil {
|
|
logger.WithError(err).Error("Error creating auth request.")
|
|
return client.LoginFailedRedirectURL
|
|
}
|
|
|
|
return response.RedirectURL
|
|
}
|
|
|
|
func (h *Handler) samlSSOConsole(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) {
|
|
logger := h.log.WithField("auth", "saml")
|
|
logger.Debug("Console login start.")
|
|
|
|
req := new(client.SSOLoginConsoleReq)
|
|
if err := httplib.ReadJSON(r, req); err != nil {
|
|
logger.WithError(err).Error("Error reading json.")
|
|
return nil, trace.AccessDenied(ssoLoginConsoleErr)
|
|
}
|
|
|
|
if err := req.CheckAndSetDefaults(); err != nil {
|
|
logger.WithError(err).Error("Missing request parameters.")
|
|
return nil, trace.AccessDenied(ssoLoginConsoleErr)
|
|
}
|
|
|
|
response, err := h.cfg.ProxyClient.CreateSAMLAuthRequest(r.Context(), types.SAMLAuthRequest{
|
|
ConnectorID: req.ConnectorID,
|
|
ClientRedirectURL: req.RedirectURL,
|
|
PublicKey: req.PublicKey,
|
|
CertTTL: req.CertTTL,
|
|
Compatibility: req.Compatibility,
|
|
RouteToCluster: req.RouteToCluster,
|
|
KubernetesCluster: req.KubernetesCluster,
|
|
AttestationStatement: req.AttestationStatement.ToProto(),
|
|
})
|
|
if err != nil {
|
|
logger.WithError(err).Error("Failed to create SAML auth request.")
|
|
return nil, trace.AccessDenied(ssoLoginConsoleErr)
|
|
}
|
|
|
|
return &client.SSOLoginConsoleResponse{RedirectURL: response.RedirectURL}, nil
|
|
}
|
|
|
|
func (h *Handler) samlACS(w http.ResponseWriter, r *http.Request, p httprouter.Params) string {
|
|
logger := h.log.WithField("auth", "saml")
|
|
logger.Debug("Callback start.")
|
|
|
|
var samlResponse string
|
|
if err := form.Parse(r, form.String("SAMLResponse", &samlResponse, form.Required())); err != nil {
|
|
logger.WithError(err).Error("Error parsing response.")
|
|
return client.LoginFailedRedirectURL
|
|
}
|
|
|
|
response, err := h.cfg.ProxyClient.ValidateSAMLResponse(r.Context(), samlResponse, p.ByName("connector"))
|
|
|
|
if err != nil {
|
|
logger.WithError(err).Error("Error while processing callback.")
|
|
|
|
// try to find the auth request, which bears the original client redirect URL.
|
|
// if found, use it to terminate the flow.
|
|
//
|
|
// this improves the UX by terminating the failed SSO flow immediately, rather than hoping for a timeout.
|
|
if requestID, errParse := auth.ParseSAMLInResponseTo(samlResponse); errParse == nil {
|
|
if request, errGet := h.cfg.ProxyClient.GetSAMLAuthRequest(r.Context(), requestID); errGet == nil && !request.CreateWebSession {
|
|
if url, errEnc := redirectURLWithError(request.ClientRedirectURL, err); errEnc == nil {
|
|
return url.String()
|
|
}
|
|
}
|
|
}
|
|
|
|
if errors.Is(err, auth.ErrSAMLNoRoles) {
|
|
return client.LoginFailedUnauthorizedRedirectURL
|
|
}
|
|
|
|
return client.LoginFailedBadCallbackRedirectURL
|
|
}
|
|
|
|
// if we created web session, set session cookie and redirect to original url
|
|
if response.Req.CreateWebSession {
|
|
logger.Debug("Redirecting to web browser.")
|
|
|
|
redirect := response.Req.ClientRedirectURL
|
|
if redirect == "" {
|
|
redirect = "/web/"
|
|
}
|
|
|
|
res := &ssoCallbackResponse{
|
|
csrfToken: response.Req.CSRFToken,
|
|
username: response.Username,
|
|
sessionName: response.Session.GetName(),
|
|
clientRedirectURL: redirect,
|
|
}
|
|
|
|
if err := ssoSetWebSessionAndRedirectURL(w, r, res, response.Req.CSRFToken != ""); err != nil {
|
|
logger.WithError(err).Error("Error setting web session.")
|
|
return client.LoginFailedRedirectURL
|
|
}
|
|
|
|
return res.clientRedirectURL
|
|
}
|
|
|
|
logger.Debug("Callback redirecting to console login.")
|
|
if len(response.Req.PublicKey) == 0 {
|
|
logger.Error("Not a web or console login request.")
|
|
return client.LoginFailedRedirectURL
|
|
}
|
|
|
|
redirectURL, err := ConstructSSHResponse(AuthParams{
|
|
ClientRedirectURL: response.Req.ClientRedirectURL,
|
|
Username: response.Username,
|
|
Identity: response.Identity,
|
|
Session: response.Session,
|
|
Cert: response.Cert,
|
|
TLSCert: response.TLSCert,
|
|
HostSigners: response.HostSigners,
|
|
})
|
|
if err != nil {
|
|
logger.WithError(err).Error("Error constructing ssh response.")
|
|
return client.LoginFailedRedirectURL
|
|
}
|
|
|
|
return redirectURL.String()
|
|
}
|