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: 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: c-operator-api-tests:
name: Operator API Tests name: Operator API Tests
@@ -912,6 +980,7 @@ jobs:
- test-restapi-on-go - test-restapi-on-go
- c-operator-api-tests - c-operator-api-tests
- test-pkg-on-go - test-pkg-on-go
- sso-integration
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
@@ -946,6 +1015,14 @@ jobs:
./integration/coverage/ ./integration/coverage/
key: ${{ runner.os }}-coverage-2-${{ github.run_id }} 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 - uses: actions/cache@v2
id: coverage-cache-operator id: coverage-cache-operator
name: Coverage Cache Operator name: Coverage Cache Operator
@@ -981,7 +1058,7 @@ jobs:
echo "go build gocoverage.go" echo "go build gocoverage.go"
go build gocovmerge.go go build gocovmerge.go
echo "put together the outs for final coverage resolution" 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" echo "grep to obtain the result"
go tool cover -func=all.out | grep total > tmp2 go tool cover -func=all.out | grep total > tmp2
result=`cat tmp2 | awk 'END {print $3}'` result=`cat tmp2 | awk 'END {print $3}'`

View File

@@ -80,6 +80,57 @@ test-integration:
@(docker stop minio) @(docker stop minio)
@(docker network rm mynet123) @(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: test-operator-integration:
@(echo "Start cd operator-integration && go test:") @(echo "Start cd operator-integration && go test:")
@(pwd) @(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)
}
}