Skip to content

Commit 46cc007

Browse files
committed
External OAuth integration test
Signed-off-by: Simo Sorce <[email protected]>
1 parent 81dc345 commit 46cc007

File tree

1 file changed

+215
-0
lines changed

1 file changed

+215
-0
lines changed
+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
package integration
2+
3+
import (
4+
"bytes"
5+
"crypto/tls"
6+
"encoding/json"
7+
"fmt"
8+
"io/ioutil"
9+
"net/http"
10+
"net/http/httptest"
11+
"os"
12+
"reflect"
13+
//"strings"
14+
"testing"
15+
16+
kauthn "k8s.io/api/authentication/v1beta1"
17+
//kerrors "k8s.io/apimachinery/pkg/api/errors"
18+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19+
"k8s.io/client-go/rest"
20+
kclientcmd "k8s.io/client-go/tools/clientcmd"
21+
kclientcmdapi "k8s.io/client-go/tools/clientcmd/api"
22+
23+
authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization"
24+
configapi "github.com/openshift/origin/pkg/cmd/server/apis/config"
25+
//oauthclient "github.com/openshift/origin/pkg/oauth/generated/internalclientset"
26+
oauthutil "github.com/openshift/origin/pkg/oauth/util"
27+
"github.com/openshift/origin/pkg/oc/util/tokencmd"
28+
userclient "github.com/openshift/origin/pkg/user/generated/internalclientset/typed/user/internalversion"
29+
testutil "github.com/openshift/origin/test/util"
30+
testserver "github.com/openshift/origin/test/util/server"
31+
)
32+
33+
// TestWebhookTokenAuthn checks Tokens directly against an external
34+
// authenticator
35+
func TestOauthExternal(t *testing.T) {
36+
authToken := "BoringToken"
37+
authTestUser := "user"
38+
authTestUID := "42"
39+
authTestGroups := []string{"testgroup"}
40+
41+
expectedTokenPost := kauthn.TokenReview{
42+
TypeMeta: metav1.TypeMeta{
43+
APIVersion: "authentication.k8s.io/v1beta1",
44+
Kind: "TokenReview",
45+
},
46+
Spec: kauthn.TokenReviewSpec{Token: authToken},
47+
}
48+
49+
tokenResponse := kauthn.TokenReview{
50+
TypeMeta: metav1.TypeMeta{
51+
APIVersion: "authentication.k8s.io/v1beta1",
52+
Kind: "TokenReview",
53+
},
54+
Status: kauthn.TokenReviewStatus{
55+
Authenticated: true,
56+
User: kauthn.UserInfo{
57+
Username: authTestUser,
58+
UID: authTestUID,
59+
Groups: authTestGroups,
60+
Extra: map[string]kauthn.ExtraValue{
61+
authorizationapi.ScopesKey: []string{
62+
"user:info",
63+
},
64+
},
65+
},
66+
},
67+
}
68+
69+
// Write cert we're going to use to verify auth server requests
70+
caFile, err := ioutil.TempFile("", "test.crt")
71+
if err != nil {
72+
t.Fatalf("unexpected error: %v", err)
73+
}
74+
defer os.Remove(caFile.Name())
75+
if err := ioutil.WriteFile(caFile.Name(), authLocalhostCert, os.FileMode(0600)); err != nil {
76+
t.Fatalf("unexpected error: %v", err)
77+
}
78+
79+
var authServerURL string
80+
81+
// Set up a dummy authenticator server
82+
authServer := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
83+
switch r.URL.Path {
84+
case "/authenticate":
85+
if r.Method != "POST" {
86+
t.Fatalf("Expected POST to /authenticate, got %s", r.Method)
87+
}
88+
if err := r.ParseForm(); err != nil {
89+
t.Fatalf("Error parsing form POSTed to /token: %v", err)
90+
}
91+
var tokenPost kauthn.TokenReview
92+
if err = json.NewDecoder(r.Body).Decode(&tokenPost); err != nil {
93+
t.Fatalf("Expected TokenReview structure in POST request: %v", err)
94+
}
95+
if !reflect.DeepEqual(tokenPost, expectedTokenPost) {
96+
t.Fatalf("Expected\n%#v\ngot\n%#v", expectedTokenPost, tokenPost)
97+
}
98+
if err = json.NewEncoder(w).Encode(tokenResponse); err != nil {
99+
t.Fatalf("Failed to encode Token Review response: %v", err)
100+
}
101+
102+
case "/oauth/authorize":
103+
w.Header().Set("Location", fmt.Sprintf("%s/oauth/token/implicit?code=%s", authServerURL, authToken))
104+
w.WriteHeader(http.StatusFound)
105+
106+
case "/oauth/token":
107+
w.Write([]byte(fmt.Sprintf(`{"access_token":%q, "token_type":"Bearer"}`, authToken)))
108+
default:
109+
t.Fatalf("Unexpected request: %v", r.URL.Path)
110+
}
111+
}))
112+
cert, err := tls.X509KeyPair(authLocalhostCert, authLocalhostKey)
113+
authServer.TLS = &tls.Config{
114+
Certificates: []tls.Certificate{cert},
115+
}
116+
authServer.StartTLS()
117+
defer authServer.Close()
118+
authServerURL = authServer.URL
119+
120+
authConfigFile, err := ioutil.TempFile("", "test.cfg")
121+
if err != nil {
122+
t.Fatalf("unexpected error: %v", err)
123+
}
124+
defer os.Remove(authConfigFile.Name())
125+
authConfigObj := kclientcmdapi.Config{
126+
Clusters: map[string]*kclientcmdapi.Cluster{
127+
"authService": {
128+
CertificateAuthority: caFile.Name(),
129+
Server: authServer.URL + "/authenticate",
130+
},
131+
},
132+
AuthInfos: map[string]*kclientcmdapi.AuthInfo{
133+
"apiServer": {
134+
ClientCertificateData: authLocalhostCert,
135+
ClientKeyData: authLocalhostKey,
136+
},
137+
},
138+
CurrentContext: "webhook",
139+
Contexts: map[string]*kclientcmdapi.Context{
140+
"webhook": {
141+
Cluster: "authService",
142+
AuthInfo: "apiServer",
143+
},
144+
},
145+
}
146+
if err := kclientcmd.WriteToFile(authConfigObj, authConfigFile.Name()); err != nil {
147+
t.Fatalf("unexpected error: %v", err)
148+
}
149+
150+
authServerMetadataFile, err := ioutil.TempFile("", "metadata.cfg")
151+
if err != nil {
152+
t.Fatalf("unexpected error: %v", err)
153+
}
154+
defer os.Remove(authServerMetadataFile.Name())
155+
authServerMetadata, err := json.MarshalIndent(oauthutil.GetOauthMetadata(authServer.URL), "", "")
156+
if err != nil {
157+
t.Fatalf("unexpected error: %v", err)
158+
}
159+
authServerMetadataFile.Write(authServerMetadata)
160+
authServerMetadataFile.Sync()
161+
authServerMetadataFile.Close()
162+
163+
// Get master config
164+
masterOptions, err := testserver.DefaultMasterOptions()
165+
if err != nil {
166+
t.Fatalf("unexpected error: %v", err)
167+
}
168+
defer testserver.CleanupMasterEtcd(t, masterOptions)
169+
170+
masterOptions.OAuthConfig = nil
171+
masterOptions.ExternalOAuthConfig = &configapi.ExternalOAuthConfig{
172+
MetadataFile: authServerMetadataFile.Name(),
173+
MasterPublicURL: masterOptions.MasterPublicURL,
174+
AssetPublicURL: masterOptions.MasterPublicURL + "/console/",
175+
}
176+
masterOptions.AuthConfig.WebhookTokenAuthenticators = []configapi.WebhookTokenAuthenticator{
177+
{
178+
ConfigFile: authConfigFile.Name(),
179+
CacheTTL: "10s",
180+
},
181+
}
182+
183+
// Start server
184+
clusterAdminKubeConfig, err := testserver.StartConfiguredMaster(masterOptions)
185+
if err != nil {
186+
t.Fatalf("unexpected error: %v", err)
187+
}
188+
clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig)
189+
if err != nil {
190+
t.Fatal(err)
191+
}
192+
193+
anonymousConfig := rest.AnonymousClientConfig(clusterAdminClientConfig)
194+
anonymousConfig.TLSClientConfig.CAData = append(anonymousConfig.TLSClientConfig.CAData, authLocalhostCert...)
195+
reader := bytes.NewBufferString("user\npass")
196+
accessToken, err := tokencmd.RequestToken(anonymousConfig, reader, "", "")
197+
if err != nil {
198+
t.Errorf("Unexpected error: %v", err)
199+
}
200+
if len(accessToken) == 0 {
201+
t.Error("Expected accessToken, but did not get one")
202+
}
203+
204+
clientConfig := rest.AnonymousClientConfig(clusterAdminClientConfig)
205+
clientConfig.BearerToken = accessToken
206+
207+
user, err := userclient.NewForConfigOrDie(clientConfig).Users().Get("~", metav1.GetOptions{})
208+
if err != nil {
209+
t.Fatal(err)
210+
}
211+
212+
if user.Name != "user" {
213+
t.Errorf("expected %v, got %v", "user", user.Name)
214+
}
215+
}

0 commit comments

Comments
 (0)