SSO Integration Test (#1742)
This commit is contained in:
committed by
GitHub
parent
b658301725
commit
d22f345d4a
79
.github/workflows/jobs.yaml
vendored
79
.github/workflows/jobs.yaml
vendored
@@ -16,6 +16,74 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
|
||||
sso-integration:
|
||||
|
||||
name: SSO Integration Test
|
||||
needs:
|
||||
- lint-job
|
||||
- no-warnings-and-make-assets
|
||||
- reuse-golang-dependencies
|
||||
- vulnerable-dependencies-checks
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ 1.17.x ]
|
||||
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# To build minio image, we need to clone the repository first
|
||||
- name: clone https://github.com/minio/minio
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
|
||||
# Repository name with owner. For example, actions/checkout
|
||||
# Default: ${{ github.repository }}
|
||||
repository: minio/minio
|
||||
|
||||
# Relative path under $GITHUB_WORKSPACE to place the repository
|
||||
# To have two repositories under the same test
|
||||
path: 'minio_repository'
|
||||
|
||||
- uses: actions/cache@v2
|
||||
name: Go Mod Cache
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ github.run_id }}
|
||||
|
||||
- name: Build on ${{ matrix.os }}
|
||||
run: |
|
||||
echo "The idea is to build minio image from downloaded repository";
|
||||
cd $GITHUB_WORKSPACE/minio_repository;
|
||||
echo "Get git version to build MinIO Image";
|
||||
VERSION=`git rev-parse HEAD`;
|
||||
echo $VERSION;
|
||||
echo "Create minio image";
|
||||
make docker VERSION=$VERSION;
|
||||
echo "Jumping back to console repository to run the integration test"
|
||||
cd $GITHUB_WORKSPACE;
|
||||
echo "We are going to use the built image on test-integration";
|
||||
VERSION="minio/minio:$VERSION";
|
||||
echo $VERSION;
|
||||
make test-sso-integration MINIO_VERSION=$VERSION;
|
||||
- uses: actions/cache@v2
|
||||
id: coverage-cache-sso
|
||||
name: Coverage Cache SSO
|
||||
with:
|
||||
path: |
|
||||
./sso-integration/coverage/
|
||||
key: ${{ runner.os }}-sso-coverage-2-${{ github.run_id }}
|
||||
|
||||
c-operator-api-tests:
|
||||
|
||||
name: Operator API Tests
|
||||
@@ -912,6 +980,7 @@ jobs:
|
||||
- test-restapi-on-go
|
||||
- c-operator-api-tests
|
||||
- test-pkg-on-go
|
||||
- sso-integration
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -946,6 +1015,14 @@ jobs:
|
||||
./integration/coverage/
|
||||
key: ${{ runner.os }}-coverage-2-${{ github.run_id }}
|
||||
|
||||
- uses: actions/cache@v2
|
||||
id: coverage-cache-sso
|
||||
name: Coverage Cache SSO
|
||||
with:
|
||||
path: |
|
||||
./sso-integration/coverage/
|
||||
key: ${{ runner.os }}-sso-coverage-2-${{ github.run_id }}
|
||||
|
||||
- uses: actions/cache@v2
|
||||
id: coverage-cache-operator
|
||||
name: Coverage Cache Operator
|
||||
@@ -981,7 +1058,7 @@ jobs:
|
||||
echo "go build gocoverage.go"
|
||||
go build gocovmerge.go
|
||||
echo "put together the outs for final coverage resolution"
|
||||
./gocovmerge ../integration/coverage/system.out ../restapi/coverage/coverage.out ../pkg/coverage/coverage-pkg.out ../operator-integration/coverage/operator-api.out > all.out
|
||||
./gocovmerge ../integration/coverage/system.out ../sso-integration/coverage/sso-system.out ../restapi/coverage/coverage.out ../pkg/coverage/coverage-pkg.out ../operator-integration/coverage/operator-api.out > all.out
|
||||
echo "grep to obtain the result"
|
||||
go tool cover -func=all.out | grep total > tmp2
|
||||
result=`cat tmp2 | awk 'END {print $3}'`
|
||||
|
||||
51
Makefile
51
Makefile
@@ -80,6 +80,57 @@ test-integration:
|
||||
@(docker stop minio)
|
||||
@(docker network rm mynet123)
|
||||
|
||||
test-sso-integration:
|
||||
@echo "create the network in bridge mode to communicate all containers"
|
||||
@(docker network create my-net)
|
||||
@echo "execute latest keycloak container"
|
||||
@(docker run \
|
||||
--rm \
|
||||
--name keycloak-container \
|
||||
--network my-net \
|
||||
-p 8080:8080 \
|
||||
-e KEYCLOAK_USER=admin \
|
||||
-e KEYCLOAK_PASSWORD=admin jboss/keycloak:latest -b 0.0.0.0 -bprivate 127.0.0.1 &)
|
||||
@echo "wait 60 sec until keycloak is listenning on port, then go for minio server"
|
||||
@(sleep 60)
|
||||
@echo "execute keycloak-config-cli container to configure keycloak for Single Sign On with MinIO"
|
||||
@(docker run \
|
||||
--rm \
|
||||
--network my-net \
|
||||
--name keycloak-config-cli \
|
||||
-e KEYCLOAK_URL=http://keycloak-container:8080/auth \
|
||||
-e KEYCLOAK_USER="admin" \
|
||||
-e KEYCLOAK_PASSWORD="admin" \
|
||||
-e KEYCLOAK_AVAILABILITYCHECK_ENABLED=true \
|
||||
-e KEYCLOAK_AVAILABILITYCHECK_TIMEOUT=120s \
|
||||
-e IMPORT_FILES_LOCATIONS='/config/realm-export.json' \
|
||||
-v /home/runner/work/console/console/sso-integration/config:/config \
|
||||
adorsys/keycloak-config-cli:latest)
|
||||
@echo "running minio server"
|
||||
@(docker run \
|
||||
-v /data1 -v /data2 -v /data3 -v /data4 \
|
||||
--network my-net \
|
||||
-d \
|
||||
--name minio \
|
||||
--rm \
|
||||
-p 9000:9000 \
|
||||
-p 9001:9001 \
|
||||
-e MINIO_IDENTITY_OPENID_CLIENT_SECRET=0nfJuqIt0iPnRIUJkvetve5l38C6gi9W \
|
||||
-e MINIO_ROOT_USER=minio \
|
||||
-e MINIO_ROOT_PASSWORD=minio123 $(MINIO_VERSION) server /data{1...4} --address :9000 --console-address :9001)
|
||||
@(sleep 60)
|
||||
@echo "run mc commands"
|
||||
@(docker run --name minio-client --network my-net -dit --entrypoint=/bin/sh minio/mc)
|
||||
@(docker exec minio-client mc alias set myminio/ http://minio:9000 minio minio123)
|
||||
@(docker exec minio-client mc admin config set myminio identity_openid config_url="http://keycloak-container:8080/auth/realms/myrealm/.well-known/openid-configuration" client_id="account")
|
||||
@(docker exec minio-client mc admin service restart myminio)
|
||||
@echo "starting bash script"
|
||||
@(env bash $(PWD)/sso-integration/set-sso.sh)
|
||||
@echo "install jq"
|
||||
@(sudo apt install jq)
|
||||
@echo "Executing the test:"
|
||||
@(cd sso-integration && go test -coverpkg=../restapi -c -tags testrunmain . && mkdir -p coverage && ./sso-integration.test -test.v -test.run "^Test*" -test.coverprofile=coverage/sso-system.out)
|
||||
|
||||
test-operator-integration:
|
||||
@(echo "Start cd operator-integration && go test:")
|
||||
@(pwd)
|
||||
|
||||
2270
sso-integration/config/realm-export.json
Normal file
2270
sso-integration/config/realm-export.json
Normal file
File diff suppressed because it is too large
Load Diff
165
sso-integration/logssorun2.sh
Executable file
165
sso-integration/logssorun2.sh
Executable file
@@ -0,0 +1,165 @@
|
||||
#!/bin/bash
|
||||
|
||||
result=`curl 'http://localhost:9001/api/v1/login' \
|
||||
-H 'Connection: keep-alive' \
|
||||
-H 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"' \
|
||||
-H 'sec-ch-ua-mobile: ?0' \
|
||||
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36' \
|
||||
-H 'sec-ch-ua-platform: "macOS"' \
|
||||
-H 'Accept: */*' \
|
||||
-H 'Sec-Fetch-Site: same-origin' \
|
||||
-H 'Sec-Fetch-Mode: cors' \
|
||||
-H 'Sec-Fetch-Dest: empty' \
|
||||
-H 'Referer: http://localhost:9001/login' \
|
||||
-H 'Accept-Language: en-CA,en;q=0.9' \
|
||||
--compressed`
|
||||
echo $result | jq '.redirect' > redirect.txt
|
||||
|
||||
|
||||
|
||||
|
||||
redirect=`cat redirect.txt | tr -d '"'`
|
||||
|
||||
|
||||
|
||||
|
||||
curl -i "$redirect" \
|
||||
-H 'Connection: keep-alive' \
|
||||
-H 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"' \
|
||||
-H 'sec-ch-ua-mobile: ?0' \
|
||||
-H 'sec-ch-ua-platform: "macOS"' \
|
||||
-H 'Upgrade-Insecure-Requests: 1' \
|
||||
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36' \
|
||||
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \
|
||||
-H 'Sec-Fetch-Site: same-site' \
|
||||
-H 'Sec-Fetch-Mode: navigate' \
|
||||
-H 'Sec-Fetch-User: ?1' \
|
||||
-H 'Sec-Fetch-Dest: document' \
|
||||
-H 'Referer: http://localhost:9001/' \
|
||||
-H 'Accept-Language: en-CA,en;q=0.9' \
|
||||
--compressed > form-cookies.txt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cat form-cookies.txt | grep Set-Cookie > first-cookies.txt
|
||||
cat first-cookies.txt | grep 'AUTH_SESSION_ID=' > AUTH_SESSION_ID.txt
|
||||
cat AUTH_SESSION_ID.txt | awk '{print $2}' > AUTH_SESSION_ID_2.txt
|
||||
sed 's/AUTH_SESSION_ID=//' AUTH_SESSION_ID_2.txt > AUTH_SESSION_ID_3.txt
|
||||
sed 's/;//' AUTH_SESSION_ID_3.txt > AUTH_SESSION_ID_4.txt
|
||||
AUTH_SESSION_ID=`cat AUTH_SESSION_ID_4.txt`
|
||||
AUTH_SESSION_ID_LEGACY=$AUTH_SESSION_ID
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cat first-cookies.txt | grep 'KC_RESTART=' > KC_RESTART.txt
|
||||
cat KC_RESTART.txt | awk '{print $2}' > KC_RESTART_2.txt
|
||||
sed 's/KC_RESTART=//' KC_RESTART_2.txt > KC_RESTART_3.txt
|
||||
sed 's/;//' KC_RESTART_3.txt > KC_RESTART_4.txt
|
||||
KC_RESTART=`cat KC_RESTART_4.txt`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cat form-cookies.txt | grep form | grep "kc-form-login" > form-in-file-saved.txt
|
||||
cat form-in-file-saved.txt | awk '{print $8}' > form-action-only.txt
|
||||
sed 's/action="//' form-action-only.txt > form-action-only-2.txt
|
||||
sed 's/"//' form-action-only-2.txt > form-action-only-3.txt
|
||||
sed 's/amp;//' form-action-only-3.txt > form-action-only-4.txt
|
||||
sed 's/amp;//' form-action-only-4.txt > form-action-only-5.txt
|
||||
sed 's/amp;//' form-action-only-5.txt > form-action-only-6.txt
|
||||
action=`cat form-action-only-6.txt`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cookies=`echo "Cookie: AUTH_SESSION_ID=${AUTH_SESSION_ID}; AUTH_SESSION_ID_LEGACY=${AUTH_SESSION_ID_LEGACY}; KC_RESTART=${KC_RESTART}" | tr -d '"'`
|
||||
curl -i "$action" \
|
||||
-X POST \
|
||||
-H 'Connection: keep-alive' \
|
||||
-H 'Cache-Control: max-age=0' \
|
||||
-H 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"' \
|
||||
-H 'sec-ch-ua-mobile: ?0' \
|
||||
-H 'sec-ch-ua-platform: "macOS"' \
|
||||
-H 'Upgrade-Insecure-Requests: 1' \
|
||||
-H 'Origin: null' \
|
||||
-H 'Content-Type: application/x-www-form-urlencoded' \
|
||||
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36' \
|
||||
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \
|
||||
-H 'Sec-Fetch-Site: same-origin' \
|
||||
-H 'Sec-Fetch-Mode: navigate' \
|
||||
-H 'Sec-Fetch-User: ?1' \
|
||||
-H 'Sec-Fetch-Dest: document' \
|
||||
-H 'Accept-Language: en-CA,en;q=0.9' \
|
||||
-H "$cookies" \
|
||||
--data-raw 'username=minio&password=minio123&credentialId=' \
|
||||
--compressed > referer-code-state.txt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cat referer-code-state.txt | grep Location > location.txt
|
||||
cat location.txt | awk '{print $2}' > location-2.txt
|
||||
location=`cat location-2.txt`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
IFS='&'
|
||||
read -ra ADDR <<< "$location"
|
||||
|
||||
echo ${ADDR[0]} > state.txt
|
||||
echo ${ADDR[2]} > code.txt
|
||||
sed 's/code=//' code.txt > code-1.txt
|
||||
code=`cat code-1.txt`
|
||||
echo $code
|
||||
echo $code > /tmp/code
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
IFS='?'
|
||||
state=`cat state.txt`
|
||||
read -ra ADDR22 <<< "$state"
|
||||
echo ${ADDR22[1]} > state-22.txt
|
||||
sed 's/%3D/=/' state-22.txt > state-22-1.txt
|
||||
sed 's/%3D/=/' state-22-1.txt > state-22-2.txt
|
||||
sed 's/state=//' state-22-2.txt > state-22-3.txt
|
||||
state=`cat state-22-3.txt`
|
||||
echo $state
|
||||
echo $state > /tmp/state
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
9
sso-integration/set-sso.sh
Executable file
9
sso-integration/set-sso.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "127.0.0.1 keycloak-container" | sudo tee -a /etc/hosts
|
||||
echo " "
|
||||
echo " "
|
||||
echo "/etc/hosts:"
|
||||
cat /etc/hosts
|
||||
echo " "
|
||||
echo " "
|
||||
168
sso-integration/sso_test.go
Normal file
168
sso-integration/sso_test.go
Normal file
@@ -0,0 +1,168 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package ssointegration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/minio/console/restapi"
|
||||
"github.com/minio/console/restapi/operations"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var token string
|
||||
|
||||
func initConsoleServer() (*restapi.Server, error) {
|
||||
|
||||
//os.Setenv("CONSOLE_MINIO_SERVER", "localhost:9000")
|
||||
|
||||
swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
noLog := func(string, ...interface{}) {
|
||||
// nothing to log
|
||||
}
|
||||
|
||||
// Initialize MinIO loggers
|
||||
restapi.LogInfo = noLog
|
||||
restapi.LogError = noLog
|
||||
|
||||
api := operations.NewConsoleAPI(swaggerSpec)
|
||||
api.Logger = noLog
|
||||
|
||||
server := restapi.NewServer(api)
|
||||
// register all APIs
|
||||
server.ConfigureAPI()
|
||||
consolePort, _ := strconv.Atoi("9090")
|
||||
|
||||
server.Host = "0.0.0.0"
|
||||
server.Port = consolePort
|
||||
restapi.Port = "9090"
|
||||
restapi.Hostname = "0.0.0.0"
|
||||
|
||||
return server, nil
|
||||
}
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
// start console server
|
||||
go func() {
|
||||
fmt.Println("start server")
|
||||
srv, err := initConsoleServer()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
log.Println("init fail")
|
||||
return
|
||||
}
|
||||
srv.Serve()
|
||||
|
||||
}()
|
||||
|
||||
fmt.Println("sleeping")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
|
||||
// execute bash script to get the code and state
|
||||
cmd, err := exec.Command("./logssorun2.sh").Output()
|
||||
if err != nil {
|
||||
fmt.Printf("error %s", err)
|
||||
}
|
||||
output := string(cmd)
|
||||
|
||||
fmt.Println(" ")
|
||||
fmt.Println(" ")
|
||||
fmt.Println("output:")
|
||||
fmt.Println(output)
|
||||
fmt.Println(" ")
|
||||
fmt.Println(" ")
|
||||
|
||||
temp := strings.Split(output, "\n")
|
||||
|
||||
fmt.Println(" ")
|
||||
fmt.Println(" ")
|
||||
fmt.Println("temp:")
|
||||
fmt.Println(temp)
|
||||
fmt.Println(" ")
|
||||
fmt.Println(" ")
|
||||
|
||||
fmt.Println("index0")
|
||||
fmt.Println(temp[0])
|
||||
|
||||
if int(len(temp)) >= 2 {
|
||||
fmt.Println("index 1")
|
||||
fmt.Println(temp[1])
|
||||
} else {
|
||||
assert.Fail("temp len is less than 2", len(temp))
|
||||
return
|
||||
}
|
||||
|
||||
// get login credentials
|
||||
codeVarIable := string(strings.TrimSpace(temp[0]))
|
||||
stateVarIabl := string(strings.TrimSpace(temp[1]))
|
||||
requestData := map[string]string{
|
||||
"code": codeVarIable,
|
||||
"state": stateVarIabl,
|
||||
}
|
||||
requestDataJSON, _ := json.Marshal(requestData)
|
||||
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
|
||||
request, _ := http.NewRequest(
|
||||
"POST",
|
||||
"http://localhost:9001/api/v1/login/oauth2/auth",
|
||||
requestDataBody,
|
||||
)
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
if response != nil {
|
||||
for _, cookie := range response.Cookies() {
|
||||
if cookie.Name == "token" {
|
||||
token = cookie.Value
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(response.Status)
|
||||
if token == "" {
|
||||
assert.Fail("authentication token not found in cookies response")
|
||||
} else {
|
||||
fmt.Println(token)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user