blob: b42c94bc023080867c188ce7088353247ae686a3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package oidc_test
import (
"bytes"
"context"
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"strings"
"time"
"github.com/Nerzal/gocloak/v11"
"github.com/PuerkitoBio/goquery"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("Oidc-Login", func() {
var (
OidcCookie []http.Cookie
)
Context("test apisix/admin/oidc/login", func() {
It("should return status-code 302", func() {
statusCode, err := accessOidcLogin()
Expect(err).ShouldNot(HaveOccurred(), "do request")
Expect(statusCode).To(Equal(http.StatusFound))
})
})
Context("test apisix/admin/oidc/callback", func() {
It("should return status-code 200", func() {
statusCode, err := accessOidcCallback(&OidcCookie)
Expect(err).ShouldNot(HaveOccurred(), "do request")
Expect(statusCode).To(Equal(http.StatusOK))
})
})
Context("access apisix/admin/routes with cookie", func() {
It("should return status-code 200", func() {
statusCode, err := accessRoutesWithCookie(true, OidcCookie)
Expect(err).ShouldNot(HaveOccurred(), "do request")
Expect(statusCode).To(Equal(http.StatusOK))
})
})
Context("access apisix/admin/oidc/logout with cookie", func() {
It("should return status-code 200", func() {
statusCode, err := accessOidcLogoutWithCookie(true, OidcCookie)
Expect(err).ShouldNot(HaveOccurred(), "do request")
Expect(statusCode).To(Equal(http.StatusOK))
})
})
Context("access apisix/admin/routes with invalid cookie", func() {
It("should return status-code 401", func() {
statusCode, err := accessRoutesWithCookie(false, OidcCookie)
Expect(err).ShouldNot(HaveOccurred(), "do request")
Expect(statusCode).To(Equal(http.StatusUnauthorized))
})
})
Context("access apisix/admin/oidc/logout with invalid cookie", func() {
It("should return status-code 403", func() {
statusCode, err := accessOidcLogoutWithCookie(false, OidcCookie)
Expect(err).ShouldNot(HaveOccurred(), "do request")
Expect(statusCode).To(Equal(http.StatusForbidden))
})
})
})
func accessOidcLogin() (int, error) {
var err error
var req *http.Request
var resp *http.Response
var Client = &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
createClientAndUser()
req, _ = http.NewRequest("GET", "http://127.0.0.1:9000/apisix/admin/oidc/login", nil)
resp, err = Client.Do(req)
if err != nil {
return 0, err
}
// return status-code
return resp.StatusCode, err
}
func createClientAndUser() string {
client := gocloak.NewClient("http://127.0.0.1:8080")
ctx := context.Background()
token, _ := client.LoginAdmin(ctx, "admin", "admin", "master")
redirectURIs := []string{"http://127.0.0.1:9000/*"}
_, _ = client.CreateClient(ctx, token.AccessToken, "master", gocloak.Client{
ClientID: gocloak.StringP("dashboard"),
Secret: gocloak.StringP("dashboard"),
RedirectURIs: &redirectURIs,
})
username := GetRandomString(3)
user := gocloak.User{
FirstName: gocloak.StringP(GetRandomString(3)),
LastName: gocloak.StringP(GetRandomString(3)),
Email: gocloak.StringP(GetRandomString(3)),
Enabled: gocloak.BoolP(true),
Username: gocloak.StringP(username),
}
id, _ := client.CreateUser(ctx, token.AccessToken, "master", user)
_ = client.SetPassword(ctx, token.AccessToken, id, "master", "password", false)
return username
}
func accessOidcCallback(OidcCookie *[]http.Cookie) (int, error) {
var authenticationUrl string
var loginUrl string
var err error
var req *http.Request
var resp *http.Response
var client = &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
username := createClientAndUser()
// access apisix/admin/oidc/login to get the authentication-url
req, _ = http.NewRequest("GET", "http://127.0.0.1:9000/apisix/admin/oidc/login", nil)
resp, err = client.Do(req)
if err != nil {
return 0, err
}
authenticationUrl = resp.Header.Get("Location")
// access the authentication-url
req, _ = http.NewRequest("GET", authenticationUrl, nil)
resp, err = client.Do(req)
if err != nil {
return 0, err
}
// get the login-url from html
body, _ := ioutil.ReadAll(resp.Body)
dom, _ := goquery.NewDocumentFromReader(strings.NewReader(string(body)))
dom.Find("#kc-form-login").Each(func(i int, selection *goquery.Selection) {
loginUrl = selection.Get(0).Attr[2].Val
})
// set username & password
formValues := url.Values{}
formValues.Set("username", username)
formValues.Set("password", "password")
formDataStr := formValues.Encode()
formDataBytes := []byte(formDataStr)
formBytesReader := bytes.NewReader(formDataBytes)
//fmt.Printf("loginUrl: %s/n", loginUrl)
req, _ = http.NewRequest("POST", loginUrl, formBytesReader)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
// set cookies
cookies := resp.Cookies()
for _, cookie := range cookies {
req.AddCookie(cookie)
}
// access the login-url to login
resp, err = client.Do(req)
if err != nil {
return 0, err
}
// access apisix/admin/oidc/login with code
callbackUrl := resp.Header.Get("Location")
req, _ = http.NewRequest("GET", callbackUrl, nil)
resp, err = client.Do(req)
if err != nil {
return 0, err
}
// save cookie
cookies = resp.Cookies()
for _, cookie := range cookies {
*OidcCookie = append(*OidcCookie, *cookie)
}
// return status-code
return resp.StatusCode, err
}
func accessRoutesWithCookie(setCookie bool, OidcCookie []http.Cookie) (int, error) {
var err error
var req *http.Request
var resp *http.Response
var client http.Client
req, _ = http.NewRequest("GET", "http://127.0.0.1:9000/apisix/admin/routes", nil)
// set cookie or not
if setCookie {
for _, cookie := range OidcCookie {
req.AddCookie(&cookie)
}
}
// access apisix/admin/routes
resp, err = client.Do(req)
if err != nil {
return 0, err
}
// return status-code
return resp.StatusCode, err
}
func accessOidcLogoutWithCookie(setCookie bool, OidcCookie []http.Cookie) (int, error) {
var err error
var req *http.Request
var resp *http.Response
var client http.Client
req, _ = http.NewRequest("GET", "http://127.0.0.1:9000/apisix/admin/oidc/logout", nil)
// set cookie or not
if setCookie {
for _, cookie := range OidcCookie {
req.AddCookie(&cookie)
}
}
// access apisix/admin/oidc/logout
resp, err = client.Do(req)
if err != nil {
return 0, err
}
// return status-code
return resp.StatusCode, err
}
func GetRandomString(l int) string {
str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
bytes := []byte(str)
var result []byte
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return string(result)
}