Files
threshold/internal/servers/controller/handlers/outgoing_interceptor.go
T

109 lines
3.0 KiB
Go
Raw Normal View History

2020-09-01 09:23:41 -07:00
package handlers
import (
"context"
2021-04-08 20:54:32 -04:00
"fmt"
2020-09-01 09:23:41 -07:00
"net/http"
"strings"
2021-04-08 20:54:32 -04:00
authtokenpb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/authtokens"
2020-09-01 09:23:41 -07:00
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
2021-04-08 20:54:32 -04:00
2020-09-01 09:23:41 -07:00
"google.golang.org/protobuf/proto"
)
const (
2021-04-08 20:54:32 -04:00
HttpOnlyCookieName = "wt-http-token-cookie"
JsVisibleCookieName = "wt-js-token-cookie"
tokenTypeField = "token_type"
finalRedirectUrlField = "final_redirect_url"
statusField = "status"
2020-09-01 09:23:41 -07:00
)
func OutgoingInterceptor(ctx context.Context, w http.ResponseWriter, m proto.Message) error {
m = m.ProtoReflect().Interface()
2021-04-08 20:54:32 -04:00
if !m.ProtoReflect().IsValid() {
// This would be the case if it's a nil pointer
w.WriteHeader(http.StatusNoContent)
return nil
}
2020-09-01 09:23:41 -07:00
switch m := m.(type) {
case *pbs.AuthenticateResponse:
2021-04-08 20:54:32 -04:00
if m.GetAttributes() == nil || m.GetAttributes().GetFields() == nil {
// We may not have a token depending on the subcommand; nothing to
// do if there are no attributes
return nil
}
fields := m.GetAttributes().GetFields()
if m.GetCommand() == "token" {
if _, ok := fields[statusField]; ok {
// For now at least status will never be anything useful so
// don't need to check on it; the mere presence is enough to
// know what to do
w.WriteHeader(http.StatusAccepted)
return nil
}
}
2021-04-08 20:54:32 -04:00
// It's a redirect
if urlField, ok := fields[finalRedirectUrlField]; ok {
u := urlField.GetStringValue()
if u == "" {
return fmt.Errorf("unable to convert final request url to string")
2020-09-01 09:23:41 -07:00
}
2021-04-08 20:54:32 -04:00
delete(fields, finalRedirectUrlField)
w.Header().Set("Location", u)
w.WriteHeader(http.StatusFound)
return nil
}
// It's a token response
if _, ok := fields[tokenTypeField]; ok {
aToken := &authtokenpb.AuthToken{}
// We may have "token_type" if it's a token, or it may not be a token at
// all, so ignore unknown fields
if err := StructToProto(m.GetAttributes(), aToken, WithDiscardUnknownFields(true)); err != nil {
return err
}
tokenType := m.GetAttributes().GetFields()[tokenTypeField].GetStringValue()
if strings.EqualFold(tokenType, "cookie") {
tok := aToken.GetToken()
if tok == "" {
// Response did not include a token, continue
return nil
}
delete(m.GetAttributes().GetFields(), "token")
half := len(tok) / 2
jsTok := http.Cookie{
Name: JsVisibleCookieName,
Value: tok[:half],
}
httpTok := http.Cookie{
Name: HttpOnlyCookieName,
Value: tok[half:],
HttpOnly: true,
}
http.SetCookie(w, &jsTok)
http.SetCookie(w, &httpTok)
2020-09-01 09:23:41 -07:00
}
}
2021-04-08 20:54:32 -04:00
case *pbs.AuthenticateLoginResponse:
if strings.EqualFold(m.GetTokenType(), "cookie") {
tok := m.GetItem().GetToken()
m.GetItem().Token = ""
half := len(tok) / 2
jsTok := http.Cookie{
Name: JsVisibleCookieName,
Value: tok[:half],
}
httpTok := http.Cookie{
Name: HttpOnlyCookieName,
Value: tok[half:],
HttpOnly: true,
}
http.SetCookie(w, &jsTok)
http.SetCookie(w, &httpTok)
}
2020-09-01 09:23:41 -07:00
}
return nil
}