17 "github.com/spf13/cast"
20func GetCertPool(paths []string, useSystemPool bool) (*x509.CertPool, error) {
22 return nil, fmt.Errorf("invalid empty list of Root CAs file paths")
25 var pool *x509.CertPool
27 rootPool, err := getSystemCertPool()
29 return nil, fmt.Errorf("unable to get SystemCertPool when append is true - #{err}")
33 pool = x509.NewCertPool()
36 return loadCertsFromPaths(paths, pool)
40func getSystemCertPool() (*x509.CertPool, error) {
41 rootPool, err := x509.SystemCertPool()
47 return nil, fmt.Errorf("SystemCertPool is empty")
53func loadCertsFromPaths(paths []string, pool *x509.CertPool) (*x509.CertPool, error) {
54 for _, path := range paths {
55 // Cert paths are a configurable option
56 data, err := os.ReadFile(path) // #nosec G304
58 return nil, fmt.Errorf("certificate authority file (%s) could not be read - %s", path, err)
60 if !pool.AppendCertsFromPEM(data) {
61 return nil, fmt.Errorf("loading certificate authority (%s) failed", path)
67// https://golang.org/src/crypto/tls/generate_cert.go as a function
68func GenerateCert(ipaddr string) ([]byte, []byte, error) {
71 priv, err := rsa.GenerateKey(rand.Reader, 2048)
76 keyBytes, err := x509.MarshalPKCS8PrivateKey(priv)
78 return nil, keyBytes, err
81 serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
83 return nil, keyBytes, err
86 notBefore := time.Now()
87 template := x509.Certificate{
88 SerialNumber: serialNumber,
90 Organization: []string{"OAuth2 Proxy Test Suite"},
93 NotAfter: notBefore.Add(time.Hour),
94 KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
96 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
98 IPAddresses: []net.IP{net.ParseIP(ipaddr)},
100 certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
101 return certBytes, keyBytes, err
104// SplitHostPort separates host and port. If the port is not valid, it returns
105// the entire input as host, and it doesn't check the validity of the host.
106// Unlike net.SplitHostPort, but per RFC 3986, it requires ports to be numeric.
107// *** taken from net/url, modified validOptionalPort() to accept ":*"
108func SplitHostPort(hostport string) (host, port string) {
111 colon := strings.LastIndexByte(host, ':')
112 if colon != -1 && validOptionalPort(host[colon:]) {
113 host, port = host[:colon], host[colon+1:]
116 if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
117 host = host[1 : len(host)-1]
123// validOptionalPort reports whether port is either an empty string
124// or matches /^:\d*$/
125// *** taken from net/url, modified to accept ":*"
126func validOptionalPort(port string) bool {
127 if port == "" || port == ":*" {
133 for _, b := range port[1:] {
134 if b < '0' || b > '9' {
141// IsEndpointAllowed checks whether the endpoint URL is allowed based
142// on an allowed domains list.
143func IsEndpointAllowed(endpoint *url.URL, allowedDomains []string) bool {
144 hostname := endpoint.Hostname()
146 for _, allowedDomain := range allowedDomains {
147 allowedHost, allowedPort := SplitHostPort(allowedDomain)
148 if allowedHost == "" {
152 if isHostnameAllowed(hostname, allowedHost) {
153 // the domain names match, now validate the ports
154 // if the allowed domain's port is '*', allow all ports
155 // if the allowed domain contains a specific port, only allow that port
156 // if the allowed domain doesn't contain a port at all, only allow empty redirect ports ie http and https
157 redirectPort := endpoint.Port()
158 if allowedPort == "*" ||
159 allowedPort == redirectPort ||
160 (allowedPort == "" && redirectPort == "") {
169func isHostnameAllowed(hostname, allowedHost string) bool {
170 // check if we have a perfect match between hostname and allowedHost
171 if hostname == strings.TrimPrefix(allowedHost, ".") ||
172 hostname == strings.TrimPrefix(allowedHost, "*.") {
176 // check if hostname is a sub domain of the allowedHost
177 if (strings.HasPrefix(allowedHost, ".") && strings.HasSuffix(hostname, allowedHost)) ||
178 (strings.HasPrefix(allowedHost, "*.") && strings.HasSuffix(hostname, allowedHost[1:])) {
185// RemoveDuplicateStr removes duplicates from a slice of strings.
186func RemoveDuplicateStr(strSlice []string) []string {
187 allKeys := make(map[string]struct{})
189 for _, item := range strSlice {
190 if _, ok := allKeys[item]; !ok {
191 allKeys[item] = struct{}{}
192 list = append(list, item)
198// CoerceClaim tries to convert the value into the destination interface type.
199// If it can convert the value, it will then store the value in the destination
201func CoerceClaim(value, dst any) error {
202 switch d := dst.(type) {
204 str, err := toString(value)
206 return fmt.Errorf("could not convert value to string: %v", err)
210 strSlice, err := toStringSlice(value)
212 return fmt.Errorf("could not convert value to string slice: %v", err)
216 *d = cast.ToBool(value)
218 return fmt.Errorf("unknown type for destination: %T", dst)
223// toStringSlice converts an interface (either a slice or single value) into
224// a slice of strings.
225func toStringSlice(value any) ([]string, error) {
226 var sliceValues []any
227 switch v := value.(type) {
231 sliceValues = []any{v}
235 for _, v := range sliceValues {
236 str, err := toString(v)
238 return nil, fmt.Errorf("could not convert slice entry to string %v: %v", v, err)
240 out = append(out, str)
245// toString coerces a value into a string.
246// If it is non-string, marshal it into JSON.
247func toString(value any) (string, error) {
248 if str, err := cast.ToStringE(value); err == nil {
252 jsonStr, err := json.Marshal(value)
256 return string(jsonStr), nil
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list