Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests setup #1

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
18 changes: 18 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
language: go

go:
- 1.4
- 1.5

sudo: false

install:
- echo $PWD
- cd $GOPATH/src/github.com/kwk/docker_auth/auth_server
- go get
- go install github.com/kwk/docker_auth/auth_server

script:
- echo $PWD
- go test -v ./...
- cd test/ && ./test-static-acl.sh
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![Build Status](https://travis-ci.org/kwk/docker_auth.svg?branch=test-for-auth-server)](https://travis-ci.org/kwk/docker_auth)

Docker Registry 2.0 authentication server
=========================================

Expand Down
1 change: 0 additions & 1 deletion auth_server/.gitignore

This file was deleted.

34 changes: 34 additions & 0 deletions auth_server/test/certs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Creation of example certificates

# Certificate and key for the auth server

The `auth.crt` and `auth.key` files have been created using this command:

```
openssl req -newkey rsa:4096 -nodes -sha256 -keyout auth.key -x509 -days 365 -out auth.crt
Generating a 4096 bit RSA private key
................................................................................................................................................................................................................++
........................................................................++
writing new private key to 'auth.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:Example State
Locality Name (eg, city) []:Example City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Company
Organizational Unit Name (eg, section) []:Example Organizational Unit
Common Name (e.g. server FQDN or YOUR name) []:auth.example.com
Email Address []:admin@auth.example.com
```

# How to list the contents of one of the certificates

```bash
openssl x509 -in auth.crt -text
```
36 changes: 36 additions & 0 deletions auth_server/test/certs/auth.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
-----BEGIN CERTIFICATE-----
MIIGUTCCBDmgAwIBAgIJAIg5BM++T0GHMA0GCSqGSIb3DQEBCwUAMIG+MQswCQYD
VQQGEwJERTEWMBQGA1UECAwNRXhhbXBsZSBTdGF0ZTEVMBMGA1UEBwwMRXhhbXBs
ZSBDaXR5MRgwFgYDVQQKDA9FeGFtcGxlIENvbXBhbnkxJDAiBgNVBAsMG0V4YW1w
bGUgT3JnYW5pemF0aW9uYWwgVW5pdDEZMBcGA1UEAwwQYXV0aC5leGFtcGxlLmNv
bTElMCMGCSqGSIb3DQEJARYWYWRtaW5AYXV0aC5leGFtcGxlLmNvbTAeFw0xNTEw
MjYxMTAzNDhaFw0xNjEwMjUxMTAzNDhaMIG+MQswCQYDVQQGEwJERTEWMBQGA1UE
CAwNRXhhbXBsZSBTdGF0ZTEVMBMGA1UEBwwMRXhhbXBsZSBDaXR5MRgwFgYDVQQK
DA9FeGFtcGxlIENvbXBhbnkxJDAiBgNVBAsMG0V4YW1wbGUgT3JnYW5pemF0aW9u
YWwgVW5pdDEZMBcGA1UEAwwQYXV0aC5leGFtcGxlLmNvbTElMCMGCSqGSIb3DQEJ
ARYWYWRtaW5AYXV0aC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBANv6wuZ8U9iW8/+RFZOwNC5mrjWdQcAGHHTebrOj0PZDfyDSbOQ6
N+/B06dKgkJe70hDXrKqQV2ABnopJjFumqJAcczVfOEcT7dQJYcRav5OGxPl6c5m
5KyBMoyFfkclrSrt553ZqbJ90rzbdkXSWobSwZ7y2zORtS91lArRwf4K4ZJWjLC0
1WUwcpXOeuez+vymhwi4c3d0RT48HLZhdy3t+S3ANE3B0jqwMsWvkfUp3uO8kOHo
ruc1XWdChxj+LfsrNsoQk11iy2OBMmk55usFQbikBRvuNvvWCSmyh5SllOEyM017
E+qqkdEE/bo68EvqLurgzo0BnsW9YaQWblr8Qg38V6pR5ny2WJdW+rI/0cqmSP1r
uOLd0JvrJIUhV1CV1EpJotlgpmxSNMWuxT8T1aWkd4LSt6VHYxySV76CcQ5BkuQ0
JFg3ynfT+M39hniXmA+XTqAb9fg13aBtnJ7wBb5+PzxxDnsGdVtefbVQdIyo/W5V
EK7XRRk3cfrH+0TNI73r4eRN+n4rYwQXiEiT86KIull+XrDVaW4noC6hxDZQuzay
42CcVnpDdnU1FPby6+GgKBzKrXrvq6jXtuOOMEOToXpjbsE2kyGiGPofcksRhEQv
bwlV8mpBB8zoHWekSMOc59KsUtk9tz7Ud6c3B+mjOEozx/7HJhYIfH4HAgMBAAGj
UDBOMB0GA1UdDgQWBBTbQYvhJfcSfEl2FC+JweoZs5KtiTAfBgNVHSMEGDAWgBTb
QYvhJfcSfEl2FC+JweoZs5KtiTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
A4ICAQC6IOLZW7rnHt1vgyUsxVcNrJZvQmWyctOyMfMYGsB5OC/LUtwOJWHc1B9v
RCwdnsZi1/TGDQrgfnE5TgROb4ysbOtPNtk9VeDS1OoJuunK8WZl2xgjyscs24Id
jJOrgMHvNvAtEIfmcjnBuqInpysh+fP3eJgcO/61iVU0bxilkeN2zRhnWGr9mIi4
IOyOh3q5tmF/6nHncgrkg1qlozzXIEcJw5X/IKcOJWJlDwWse4lXj3fjK8SvPxz6
JNuLgoVtcT75ZbjHzRrY3n6m2jj+LFuclDs1tLRImMvGrtNleW5ZwUgnMK8367hH
r7GpnVAnnSuKQz7n7efHnHXNet0fakT/4Ie9IbLnvREefBeYNA+P/ugi5MWKIJuR
ALQASAcq/wiMnZ0aWUj2qN5KLM0u+9tRe+GPHF9+ii9McIo+kcPH0opZCLUIx8uw
MwNoaA11xu21+kLgyvMGk2InDgazjiyDSuNbGx9mUH0cGttl+4VtmmMQMkZ0uhf9
fKQb9Fyen+yXPRdrtW+atfnIHa8IM7pm36yQ926JM4cEroqYplXSkOfx9mjEzKWv
YlfEbz3AHB/QG0Kq5lMSOw7fPgNS2iwnwKPwDh0qvyQTIfA/pPQ6qPmr5OOO1+PT
QrWHAjG3qbI3vgzDab32kwevjChelqmfoQyqT0wMypMYmD2L6Q==
-----END CERTIFICATE-----
52 changes: 52 additions & 0 deletions auth_server/test/certs/auth.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
my7FsXDuRNUL8epD5iO7hhddN53Yig==
-----END PRIVATE KEY-----
151 changes: 151 additions & 0 deletions auth_server/test/common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/bin/bash

# Outputs everything to stderr with a UTC datetime prefixed in braces "[]"
log() {
echo "[$(date -u)] $@" 1>&2
}

# Outputs everything to stderr
logtest() {
echo -e "$@" 1>&2
}

# Prints a summary of passed and failed tests and shows where to find the logs.
# Then the server is stopped.
cleanup() {
EXITCODE=0
if [ "$NUMERRORS" != "0" ]; then
log "$NUMERRORS of $NUMTESTS tests were failing:"
echo "" 1>&2
echo "----------------------------------------------------------------" 1>&2
cat $FAILEDTESTS 1>&2
echo "----------------------------------------------------------------" 1>&2
echo "" 1>&2
EXITCODE=1
else
log "All $NUMTESTS tests were passing!"
fi
log "Logs are in $LOGDIR"
log "Shutting down $PROGNAME"
# Shutdown auth_server process if it is still running
killall $PROGNAME
cd $OLDPWD
exit $EXITCODE
}

# Encode to Base64-URL without padding.
function base64UrlEncode {
echo -n "$1" | openssl enc -a -A | tr -d '=' | tr '/+' '_-'
}

# Decode from Base64-URL without padding.
function base64UrlDecode {
_l=$((${#1} % 4))
if [ $_l -eq 2 ]; then _s="$1"'=='
elif [ $_l -eq 3 ]; then _s="$1"'='
else _s="$1" ; fi
echo "$_s" | tr '_-' '/+' | openssl enc -d -a -A
}


# Sets up some paths and variables and builds or reuses the auth_server artifact.
# The first argument must be the path to the config file to be used by the
# auth_server.
setuptest() {
if [ "$#" != "1" ]; then
log "You must specify a config file for the auth_server."
exit 2
fi

trap "cleanup" EXIT
THISDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # directory of this script
PROGNAME=auth_server
OLDPWD=$PWD
LOGDIR=$(mktemp -d)
NUMERRORS=0
NUMTESTS=0
FAILEDTESTS=$LOGDIR/failed_tests.txt
CONFIGFILE=$1
PUBKEYFILE=$LOGDIR/pubkey.pem

log "Extract public key from certificate once"
openssl x509 -pubkey -noout -in $TESTDIR/certs/auth.crt > $PUBKEYFILE

# If the ENV_NOCOLOR environment variable is set, don't output colorful reports.
set +u
if [ -z "$ENV_NOCOLOR" ]; then
COLOR_ERROR='\033[0;31m' # Red
COLOR_SUCCESS='\033[0;32m' # Green
COLOR_NONE='\033[0m' # No Color
else
COLOR_ERROR=''
COLOR_SUCCESS=''
COLOR_NONE='' # No Color
fi
set -u

# Build the auth_server or reuse an existing artifact
cd $TESTDIR/..
if [ ! -e "$PROGNAME" ]; then
log "Building $PROGNAME"
go build
else
log "Found already existing $PROGNAME (skipping build)."
fi
}

# Starts the auth_server and fires an authorization requests to it to see if it
# is responding correctly. Then, the server is shutdown.
#
# The inputs are:
#
# 1. Expected Result Code (e.g. "200", or "401")
# 2. The auth Header with which to authenticate, e.g. "Authorization: Basic $(echo -n "test:123" | base64)"
# 3. The URL to try, e.g. "https://localhost:5001/auth?service=registry.docker.io&scope=repository:somenamespace/somerepo,pull,push"
# 4. A message to describe the test.
testAuth() {
expectedResponseCode=$1
authHeader="$2"
URL="$3"
msg=$4

NUMTESTS=$((NUMTESTS+1))
LOGFILE=$LOGDIR/$PROGNAME.log.$NUMTESTS
OUTFILE=$LOGDIR/$PROGNAME.out.$NUMTESTS

# Start the auth server
./$PROGNAME -v 5 -alsologtostderr=true $CONFIGFILE > $LOGFILE 2>&1 & #-log_dir=$LOGDIR
sleep 2

FAILED=0

respCode=$(curl -sk --output "$OUTFILE" --write-out '%{http_code}' -H "$authHeader" "$URL")
if [ "$respCode" != "$expectedResponseCode" ]; then
FAILED=1
else
# Analyse the token we received

TOKEN=$(cat $OUTFILE | jq ".token" | tr -d '"')
HEADER=$(base64UrlDecode $(echo $TOKEN | cut -d '.' -f 1))
PAYLOAD=$(base64UrlDecode $(echo $TOKEN | tr -d '"' | cut -d '.' -f 2))
SIGNATURE=$(base64UrlDecode $(echo $TOKEN | tr -d '"' | cut -d '.' -f 3))

# Verify the signature
# TODO (kwk) Either implement in bash or switch to Go and docker/libtrust instead
fi

if [ "$FAILED" == "1" ]; then
echo -e "${COLOR_ERROR}TEST FAILED: $msg${COLOR_NONE}" | tee --append $FAILEDTESTS 1>&2
echo -e " - Expected $expectedResponseCode and got \"$respCode\" with authHeader=\"$authHeader\" and URL=\"$URL\"" 1>&2
echo -e "------------------------- LOG ------------------------------" 1>&2
cat $LOGFILE
echo -e "----------------------------------------------------------------" 1>&2
#cat $LOGDIR/$PROGNAME.* 1>&2
NUMERRORS=$((NUMERRORS+1))
#exit 2
else
logtest "${COLOR_SUCCESS}TEST PASSED: $msg${COLOR_NONE}"
fi

killall $PROGNAME
}
65 changes: 65 additions & 0 deletions auth_server/test/config/static-acls.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# See reference.yml for explanation for explanation of all options.

server:
addr: ":5001"
certificate: "test/certs/auth.crt"
key: "test/certs/auth.key"

token:
issuer: "Acme auth server" # Must match issuer in the Registry config.
expiration: 900

users:
# Password is specified as a BCrypt hash. Use htpasswd -B to generate.
"admin":
password: "$2y$05$LO.vzwpWC5LZGqThvEfznu8qhb5SGqvBSWY1J3yZ4AxtMRZ3kN5jC" # badmin
"test":
password: "$2y$05$WuwBasGDAgr.QCbGIjKJaep4dhxeai9gNZdmBnQXqpKly57oNutya" # 123
"test1":
password: "$2y$05$WuwBasGDAgr.QCbGIjKJaep4dhxeai9gNZdmBnQXqpKly57oNutya" # 123
"test2":
password: "$2y$05$WuwBasGDAgr.QCbGIjKJaep4dhxeai9gNZdmBnQXqpKly57oNutya" # 123

# ACL specifies who can do what. If the match section of an entry matches the
# request, the set of allowed actions will be applied to the token request
# and a ticket will be issued only for those of the requested actions that are
# allowed by the rule.
# * It is possible to match on user's name ("account"), subject type ("type")
# and name ("name"; for type=repository which, at the timeof writing, is the
# only known subject type, this is the image name).
# * Matches are evaluated as shell file name patterns ("globs") by default,
# so "foobar", "f??bar", "f*bar" are all valid. For even more flexibility
# match patterns can be evaluated as regexes by enclosing them in //, e.g.
# "/(foo|bar)/".
# * ACL is evaluated in the order it is defined until a match is found.
# * Empty match clause matches anything, it only makes sense at the end of the
# list and can be used as a way of specifying default permissions.
# * Empty actions set means "deny everything". Thus, a rule with `actions: []`
# is in effect a "deny" rule.
# * A special set consisting of a single "*" action means "allow everything".
# * If no match is found the default is to deny the request.
#
# You can use the following variables from the ticket request in any field:
# * ${account} - the account name, currently the same as authenticated user's name.
# * ${service} - the service name, specified by auth.token.service in the registry config.
# * ${type} - the type of the entity, normally "repository".
# * ${name} - the name of the repository (i.e. image), e.g. centos.
acl:
# Admin has full access to everything.
- match: {account: "admin"}
actions: ["*"]
# User "test" has full access to test-* images but nothing else.
- match: {account: "test", name: "test-*"}
actions: ["*"]
- match: {account: "test"}
actions: []
# All logged in users can pull all images.
- match: {account: "/.+/"}
actions: ["pull"]
# All logged in users can push all images that are in a namespace beginning with their name
- match: {account: "/.+/", name: "${account}/*"}
actions: ["*"]
# Anonymous users can pull "hello-world".
- match: {account: "", name: "hello-world"}
actions: ["pull"]
# Access is denied by default.
Loading