github.com/greenpau/go-authcrunch@v1.1.4/pkg/authn/handle_json_whoami.go (about) 1 // Copyright 2022 Paul Greenberg greenpau@outlook.com 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package authn 16 17 import ( 18 "context" 19 "encoding/json" 20 "github.com/greenpau/go-authcrunch/pkg/requests" 21 "github.com/greenpau/go-authcrunch/pkg/user" 22 "go.uber.org/zap" 23 "net/http" 24 "strings" 25 "time" 26 ) 27 28 func (p *Portal) handleJSONWhoami(ctx context.Context, w http.ResponseWriter, r *http.Request, rr *requests.Request, usr *user.User) error { 29 if usr == nil { 30 return p.handleJSONError(ctx, w, http.StatusUnauthorized, "Access denied") 31 } 32 33 // Check whether probe is being requested. 34 probeEnabled := r.URL.Query().Get("probe") 35 if probeEnabled == "true" && usr.Claims != nil { 36 respMap := make(map[string]interface{}) 37 for k, v := range usr.AsMap() { 38 respMap[k] = v 39 } 40 expiresIn := usr.Claims.ExpiresAt - time.Now().Unix() 41 respMap["authenticated"] = true 42 respMap["expires_in"] = expiresIn 43 respBytes, _ := json.Marshal(respMap) 44 w.WriteHeader(200) 45 w.Write(respBytes) 46 return nil 47 } 48 49 // Check whether id_token is being requested. 50 identityTokenEnabled := r.URL.Query().Get("id_token") 51 if identityTokenEnabled != "true" || usr.Claims == nil { 52 return p.handleJSONWhoamiPlain(ctx, w, usr) 53 } 54 55 // Locate the realm based on the issuer of the user's token. 56 realm := extractRealmFromIssuer(usr.Claims.Issuer, "oauth2") 57 if realm == "" { 58 return p.handleJSONWhoamiPlain(ctx, w, usr) 59 } 60 61 // Locate the identity provider based on the realm. 62 provider := p.getIdentityProviderByRealm(realm) 63 if provider == nil { 64 p.logger.Warn( 65 "failed returning id_token", 66 zap.String("session_id", rr.Upstream.SessionID), 67 zap.String("request_id", rr.ID), 68 zap.String("error", "realm not found"), 69 ) 70 return p.handleJSONWhoamiPlain(ctx, w, usr) 71 } 72 73 // Check whether the provider has identity token cookie configured. 74 if provider.GetIdentityTokenCookieName() == "" { 75 p.logger.Debug( 76 "failed returning id_token", 77 zap.String("session_id", rr.Upstream.SessionID), 78 zap.String("request_id", rr.ID), 79 zap.String("error", "identity token cookie name is empty"), 80 ) 81 return p.handleJSONWhoamiPlain(ctx, w, usr) 82 } 83 84 // Iterate over cookies to find the identity token cookie. 85 cookie, err := r.Cookie(provider.GetIdentityTokenCookieName()) 86 if err != nil { 87 p.logger.Debug( 88 "failed returning id_token", 89 zap.String("session_id", rr.Upstream.SessionID), 90 zap.String("request_id", rr.ID), 91 zap.String("error", "identity token cookie not found"), 92 ) 93 return p.handleJSONWhoamiPlain(ctx, w, usr) 94 } 95 96 respMap := make(map[string]interface{}) 97 for k, v := range usr.AsMap() { 98 respMap[k] = v 99 } 100 respMap["id_token"] = cookie.Value 101 respBytes, _ := json.Marshal(respMap) 102 w.WriteHeader(200) 103 w.Write(respBytes) 104 return nil 105 } 106 107 func (p *Portal) handleJSONWhoamiPlain(ctx context.Context, w http.ResponseWriter, usr *user.User) error { 108 respBytes, _ := json.Marshal(usr.AsMap()) 109 w.WriteHeader(200) 110 w.Write(respBytes) 111 return nil 112 } 113 114 func extractRealmFromIssuer(s, sp string) string { 115 var ready bool 116 for _, k := range strings.Split(s, "/") { 117 if k == sp { 118 ready = true 119 continue 120 } 121 if ready { 122 return k 123 } 124 } 125 return "" 126 }