SSO Integration Test (#1742)

This commit is contained in:
Cesar Celis Hernandez
2022-03-24 23:11:42 -04:00
committed by GitHub
parent b658301725
commit d22f345d4a
6 changed files with 2741 additions and 1 deletions

View File

@@ -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}'`

View File

@@ -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)

File diff suppressed because it is too large Load Diff

165
sso-integration/logssorun2.sh Executable file
View 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
View 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
View 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)
}
}