/
discovery.go
137 lines (116 loc) · 5.91 KB
/
discovery.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package util
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/url"
"github.com/RangelReale/osin"
"k8s.io/klog"
osinv1 "github.com/openshift/api/osin/v1"
"github.com/openshift/origin/pkg/authorization/authorizer/scope"
configapi "github.com/openshift/origin/pkg/cmd/server/apis/config"
"github.com/openshift/origin/pkg/oauth/apis/oauth/validation"
"github.com/openshift/origin/pkg/oauth/urls"
)
// OauthAuthorizationServerMetadata holds OAuth 2.0 Authorization Server Metadata used for discovery
// https://tools.ietf.org/html/draft-ietf-oauth-discovery-04#section-2
type OauthAuthorizationServerMetadata struct {
// The authorization server's issuer identifier, which is a URL that uses the https scheme and has no query or fragment components.
// This is the location where .well-known RFC 5785 [RFC5785] resources containing information about the authorization server are published.
Issuer string `json:"issuer"`
// URL of the authorization server's authorization endpoint [RFC6749].
AuthorizationEndpoint string `json:"authorization_endpoint"`
// URL of the authorization server's token endpoint [RFC6749].
TokenEndpoint string `json:"token_endpoint"`
// JSON array containing a list of the OAuth 2.0 [RFC6749] scope values that this authorization server supports.
// Servers MAY choose not to advertise some supported scope values even when this parameter is used.
ScopesSupported []string `json:"scopes_supported"`
// JSON array containing a list of the OAuth 2.0 response_type values that this authorization server supports.
// The array values used are the same as those used with the response_types parameter defined by "OAuth 2.0 Dynamic Client Registration Protocol" [RFC7591].
ResponseTypesSupported osin.AllowedAuthorizeType `json:"response_types_supported"`
// JSON array containing a list of the OAuth 2.0 grant type values that this authorization server supports.
// The array values used are the same as those used with the grant_types parameter defined by "OAuth 2.0 Dynamic Client Registration Protocol" [RFC7591].
GrantTypesSupported osin.AllowedAccessType `json:"grant_types_supported"`
// JSON array containing a list of PKCE [RFC7636] code challenge methods supported by this authorization server.
// Code challenge method values are used in the "code_challenge_method" parameter defined in Section 4.3 of [RFC7636].
// The valid code challenge method values are those registered in the IANA "PKCE Code Challenge Methods" registry [IANA.OAuth.Parameters].
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"`
}
// TODO: promote this struct as it is not effectively part of our API, since we
// validate configuration using LoadOAuthMetadataFile
func getOauthMetadata(masterPublicURL string) OauthAuthorizationServerMetadata {
return OauthAuthorizationServerMetadata{
Issuer: masterPublicURL,
AuthorizationEndpoint: urls.OpenShiftOAuthAuthorizeURL(masterPublicURL),
TokenEndpoint: urls.OpenShiftOAuthTokenURL(masterPublicURL),
// Note: this list is incomplete, which is allowed per the draft spec
ScopesSupported: scope.DefaultSupportedScopes(),
ResponseTypesSupported: osin.AllowedAuthorizeType{osin.CODE, osin.TOKEN},
GrantTypesSupported: osin.AllowedAccessType{osin.AUTHORIZATION_CODE, osin.AccessRequestType("implicit")},
CodeChallengeMethodsSupported: validation.CodeChallengeMethodsSupported,
}
}
func validateURL(urlString string) error {
urlObj, err := url.Parse(urlString)
if err != nil {
return fmt.Errorf("%q is an invalid URL: %v", urlString, err)
}
if len(urlObj.Scheme) == 0 {
return fmt.Errorf("must contain a valid scheme")
}
if len(urlObj.Host) == 0 {
return fmt.Errorf("must contain a valid host")
}
return nil
}
func LoadOAuthMetadataFile(metadataFile string) ([]byte, *OauthAuthorizationServerMetadata, error) {
data, err := ioutil.ReadFile(metadataFile)
if err != nil {
return nil, nil, fmt.Errorf("unable to read External OAuth Metadata file: %v", err)
}
oauthMetadata := &OauthAuthorizationServerMetadata{}
if err := json.Unmarshal(data, oauthMetadata); err != nil {
return nil, nil, fmt.Errorf("unable to decode External OAuth Metadata file: %v", err)
}
if err := validateURL(oauthMetadata.Issuer); err != nil {
return nil, nil, fmt.Errorf("error validating External OAuth Metadata Issuer field: %v", err)
}
if err := validateURL(oauthMetadata.AuthorizationEndpoint); err != nil {
return nil, nil, fmt.Errorf("error validating External OAuth Metadata AuthorizationEndpoint field: %v", err)
}
if err := validateURL(oauthMetadata.TokenEndpoint); err != nil {
return nil, nil, fmt.Errorf("error validating External OAuth Metadata TokenEndpoint field: %v", err)
}
return data, oauthMetadata, nil
}
func PrepOauthMetadata(oauthConfig *osinv1.OAuthConfig, oauthMetadataFile string) ([]byte, *OauthAuthorizationServerMetadata, error) {
if len(oauthMetadataFile) > 0 {
return LoadOAuthMetadataFile(oauthMetadataFile)
}
if oauthConfig != nil && len(oauthConfig.MasterPublicURL) != 0 {
metadataStruct := getOauthMetadata(oauthConfig.MasterPublicURL)
metadata, err := json.MarshalIndent(metadataStruct, "", " ")
if err != nil {
klog.Errorf("Unable to initialize OAuth authorization server metadata route: %v", err)
return nil, nil, err
}
return metadata, &metadataStruct, nil
}
return nil, nil, nil
}
// Deprecated
func DeprecatedPrepOauthMetadata(oauthConfig *configapi.OAuthConfig, oauthMetadataFile string) ([]byte, *OauthAuthorizationServerMetadata, error) {
if oauthConfig != nil {
metadataStruct := getOauthMetadata(oauthConfig.MasterPublicURL)
metadata, err := json.MarshalIndent(metadataStruct, "", " ")
if err != nil {
klog.Errorf("Unable to initialize OAuth authorization server metadata route: %v", err)
return nil, nil, err
}
return metadata, &metadataStruct, nil
}
if len(oauthMetadataFile) > 0 {
return LoadOAuthMetadataFile(oauthMetadataFile)
}
return nil, nil, nil
}