github.com/minio/console@v1.4.1/pkg/auth/idp/oauth2/proxy.go (about) 1 // This file is part of MinIO Console Server 2 // Copyright (c) 2021 MinIO, Inc. 3 // 4 // This program is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Affero General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Affero General Public License for more details. 13 // 14 // You should have received a copy of the GNU Affero General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 package oauth2 18 19 import ( 20 "net/http" 21 "regexp" 22 "strings" 23 ) 24 25 var ( 26 // De-facto standard header keys. 27 xForwardedProto = http.CanonicalHeaderKey("X-Forwarded-Proto") 28 xForwardedScheme = http.CanonicalHeaderKey("X-Forwarded-Scheme") 29 ) 30 31 var ( 32 // RFC7239 defines a new "Forwarded: " header designed to replace the 33 // existing use of X-Forwarded-* headers. 34 // e.g. Forwarded: for=192.0.2.60;proto=https;by=203.0.113.43 35 forwarded = http.CanonicalHeaderKey("Forwarded") 36 // Allows for a sub-match of the first value after 'for=' to the next 37 // comma, semi-colon or space. The match is case-insensitive. 38 forRegex = regexp.MustCompile(`(?i)(?:for=)([^(;|,| )]+)(.*)`) 39 // Allows for a sub-match for the first instance of scheme (http|https) 40 // prefixed by 'proto='. The match is case-insensitive. 41 protoRegex = regexp.MustCompile(`(?i)^(;|,| )+(?:proto=)(https|http)`) 42 ) 43 44 // getSourceScheme retrieves the scheme from the X-Forwarded-Proto and RFC7239 45 // Forwarded headers (in that order). 46 func getSourceScheme(r *http.Request) string { 47 var scheme string 48 49 // Retrieve the scheme from X-Forwarded-Proto. 50 if proto := r.Header.Get(xForwardedProto); proto != "" { 51 scheme = strings.ToLower(proto) 52 } else if proto = r.Header.Get(xForwardedScheme); proto != "" { 53 scheme = strings.ToLower(proto) 54 } else if proto := r.Header.Get(forwarded); proto != "" { 55 // match should contain at least two elements if the protocol was 56 // specified in the Forwarded header. The first element will always be 57 // the 'for=', which we ignore, subsequently we proceed to look for 58 // 'proto=' which should precede right after `for=` if not 59 // we simply ignore the values and return empty. This is in line 60 // with the approach we took for returning first ip from multiple 61 // params. 62 if match := forRegex.FindStringSubmatch(proto); len(match) > 1 { 63 if match = protoRegex.FindStringSubmatch(match[2]); len(match) > 1 { 64 scheme = strings.ToLower(match[2]) 65 } 66 } 67 } 68 69 return scheme 70 }