123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- /*
- * 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)
- }
|