Skip to content

Initial version #1

Merged
merged 2 commits into from Feb 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
75 changes: 75 additions & 0 deletions README.md
@@ -1,2 +1,77 @@
# docker-shib-test
A Shibboleth SAML test environment for Docker containers

_(Based on https://github.internet2.edu/docker/shib-idp/tree/master/test-compose)_

This repository contains a docker-compose configuration to create a SAML test
environment with the following containers:

* LDAP server
* SAML identity provider (Shibboleth IdP)
* SAML-authenticating reverse proxy (Shibboleth SP)
* Simple web application
* Acceptance test runner


## Quick Start

To start all required containers and run automated tests:

```
docker-compose up test
```

To stop all containers:

```
docker-compose down
```


## Interacting with the Environment

### Prerequisites

To interact with the test environment, you'll need to update your /etc/hosts
file to include "idp.example.edu" and "sptest.example.edu" aliases for
localhost:

```
# /etc/hosts
127.0.0.1 localhost idp.example.edu sptest.example.edu
```

### Logging in to the Test Application

To start the proxy and its dependencies:

```
docker-compose up proxy
```

To login, visit https://sptest.example.edu:8443 in a web browser. Log in with
username "banderson", password "password". If login succeeds, you'll see
phpinfo() output with HTTP headers X-Forwarded-User and X-Forwarded-Groups
populated.

Press Ctrl-C to stop the containers and return to the command line.


To stop and remove all containers:

```
docker-compose down
```


## FAQ

### Replacing keys and certificates

### Running on cloud providers

### CloudFormation template

### Terraform configuration

### Replacing test components
28 changes: 28 additions & 0 deletions ci/build.sh
@@ -0,0 +1,28 @@
#!/usr/bin/env bash

echo "[INFO] $0 started at $(date)"

# Read the commit hash
read -r COMMIT_HASH<<<"$(git rev-parse --short HEAD)"
if [ -z "$COMMIT_HASH" ]; then
echo "[ERROR] Couldn't read commit hash"
exit 1
fi
echo "[INFO] Commit hash: \"$COMMIT_HASH\""

IMAGES=( shib-test-idp test-ldap )

for IMAGE in ${IMAGES[*]}; do
echo "[INFO] Building $IMAGE"
cd containers/"$IMAGE" || exit 1
docker build --pull --quiet --tag "$IMAGE":latest \
--tag "$IMAGE":"$COMMIT_HASH" .
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
echo "[ERROR] Building $IMAGE failed (exit code $EXIT_CODE)"
exit 1
fi
cd ../..
done

echo "[INFO] $0 finished at $(date)"
78 changes: 78 additions & 0 deletions ci/deploy.sh
@@ -0,0 +1,78 @@
#!/usr/bin/env bash

# Environment variables:
#
# REPOSITORY_URI (Optional)

echo "[INFO] $0 started at $(date)"

images=( shib-test-idp test-ldap )

# Get the commit hash
read -r commit_hash<<<"$(git rev-parse --short HEAD)"
echo "[INFO] Commit hash: \"$commit_hash\""

for image in "${images[@]}"
do
echo "[INFO] Building the $image image"

cd containers/"$image" || exit 1

# Get the image version from the label
read -r version<<<"$(docker inspect --format='{{.Config.Labels.version}}' "$image":"$commit_hash")"
if [ -z "$version" ]; then
echo "[ERROR] Unable to inspect version label for image $image:$commit_hash"
exit 1
fi
echo "[INFO] Version: $version"
read -r major minor patch<<<"$(echo """$version""" | tr . ' ')"
echo "[DEBUG] major.minor.patch=\"$major.$minor.$patch\""
local_image="$image:$commit_hash"
echo "[DEBUG] local_image=\"$local_image\""

# If no ECR hostname is set, default to using Docker Hub
if [ -z "$REPOSITORY_URI" ]; then
remote_image_uri="${image}"
else
remote_image_uri="${REPOSITORY_URI}/${image}"
fi
echo "[DEBUG] image_uri=$remote_image_uri"

# Determine tags to apply
tags=(
"latest"
"$major.$minor.$patch"
"$major.$minor"
"$major"
)
echo "[DEBUG] tags=\"${tags[*]}\""

# Tag the image
echo "[INFO] Tagging the $image image"
for tag in "${tags[@]}"; do
cmd="docker tag $local_image $remote_image_uri:$tag"
echo "[DEBUG] cmd=\"$cmd\""
if ! $cmd
then
echo "[ERROR] Tagging the $image image with \"$tag\" failed (exit code $rc)"
exit 1
fi
done

# Push the image to the registry
echo "[INFO] Pushing the image to the registry"
for tag in "${tags[@]}"; do
cmd="docker push $remote_image_uri:$tag"
echo "[DEBUG] cmd=\"$cmd\""
$cmd
rc=$?
if [ $rc -ne 0 ]; then
echo "[ERROR] Push failed (exit code $rc)"
exit 1
fi
done

cd ../..
done

echo "[INFO] $0 finished at $(date)"
4 changes: 4 additions & 0 deletions ci/login.sh
@@ -0,0 +1,4 @@
#!/usr/bin/env bash

echo "Logging in to ECR repository"
$(aws ecr get-login --no-include-email)
34 changes: 34 additions & 0 deletions ci/test.sh
@@ -0,0 +1,34 @@
#!/usr/bin/env bash

# Run automated tests
#
# Example:
#
# ci/test.sh
#
# Returns exit code 0 on success, or 1 on failure

echo "[INFO] $0 started at $(date)"

# Set default exit code to return
EXIT_CODE=0

# Bring up the test container and its dependencies
echo "[INFO] Starting test container"
if ! docker-compose up --force-recreate --quiet-pull --renew-anon-volumes test
then
echo "[ERROR] Test container failed (exit code $?)"
EXIT_CODE=1
fi

# Shut down the containers
echo "[INFO] Shutting down containers"
if ! docker-compose down --volumes
then
echo "[ERROR] Shutting down containers failed (exit code $?)"
EXIT_CODE=1
fi

echo "[INFO] $0 finished at $(date)"

exit $EXIT_CODE
22 changes: 22 additions & 0 deletions containers/shib-test-idp/Dockerfile
@@ -0,0 +1,22 @@
FROM tier/shib-idp:3.4.6_20200107

LABEL version="0.0.1"

# Copy in the needed config files
COPY container_files/config/tomcat /usr/local/tomcat/conf
COPY container_files/credentials/tomcat /opt/certs
COPY container_files/wwwroot /usr/local/tomcat/webapps/ROOT
COPY container_files/config/shib-idp/conf /opt/shibboleth-idp/conf
COPY container_files/credentials/shib-idp /opt/shibboleth-idp/credentials
COPY container_files/config/shib-idp/views /opt/shibboleth-idp/views
COPY container_files/config/shib-idp/edit-webapp /opt/shibboleth-idp/edit-webapp
COPY container_files/config/shib-idp/messages /opt/shibboleth-idp/messages
COPY container_files/config/shib-idp/metadata /opt/shibboleth-idp/metadata

# Create an entrypoint to insert some startup tasks
COPY --chown=root:root container_files/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod 755 /usr/local/bin/entrypoint.sh
ENTRYPOINT [ "/usr/local/bin/entrypoint.sh" ]

# Run the base image's startup script after the entrypoint
CMD [ "/usr/bin/startup.sh" ]
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"

default-init-method="initialize"
default-destroy-method="destroy">

<!--
Map of access control policies used to limit access to administrative functions.
The purpose of the map is to label policies with a key/name so they can be reused.
-->

<!--
Use the "shibboleth.IPRangeAccessControl" parent bean for IP-based access control.
The ranges provided MUST be CIDR network expressions. To specify a single address,
add "/32" or "/128" for IPv4 or IPv6 respectively.
The additional examples below demonstrate how to control access by username
and by attribute(s), in the case of authenticated access to admin functions.
-->

<util:map id="shibboleth.AccessControlPolicies">

<entry key="AccessByIPAddress">
<bean id="AccessByIPAddress" parent="shibboleth.IPRangeAccessControl"
p:allowedRanges="#{ {'127.0.0.1/32', '::1/128', '172.17.0.0/24', '172.18.0.0/24', '10.255.0.0/16'} }" />
</entry>

<!--
<entry key="AccessByUser">
<bean parent="shibboleth.PredicateAccessControl">
<constructor-arg>
<bean parent="shibboleth.Conditions.SubjectName" c:collection="#{'jdoe'}" />
</constructor-arg>
</bean>
</entry>
-->

<!--
<entry key="AccessByAttribute">
<bean parent="shibboleth.PredicateAccessControl">
<constructor-arg>
<bean class="net.shibboleth.idp.profile.logic.SimpleAttributePredicate">
<property name="attributeValueMap">
<map>
<entry key="eduPersonEntitlement">
<list>
<value>https://example.org/entitlement/idpadmin</value>
</list>
</entry>
</map>
</property>
</bean>
</constructor-arg>
</bean>
</entry>
-->

</util:map>

</beans>
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"

default-init-method="initialize"
default-destroy-method="destroy">

<util:list id="shibboleth.AvailableAdminFlows">

<!-- Status Page -->
<bean parent="shibboleth.AdminFlow"
c:id="http://shibboleth.net/ns/profiles/status"
p:loggingId="%{idp.service.logging.status:Status}"
p:policyName="%{idp.status.accessPolicy:AccessByIPAddress}" />

<!-- Service Reload -->
<bean parent="shibboleth.AdminFlow"
c:id="http://shibboleth.net/ns/profiles/reload-service-configuration"
p:loggingId="%{idp.service.logging.serviceReload:Reload}"
p:policyName="%{idp.reload.accessPolicy:AccessByIPAddress}" />

<!-- MetadataResolver Reload -->
<bean parent="shibboleth.AdminFlow"
c:id="http://shibboleth.net/ns/profiles/reload-metadata"
p:loggingId="%{idp.service.logging.serviceReload:Reload}"
p:policyName="%{idp.reload.accessPolicy:AccessByIPAddress}" />

<!-- AttributeResolver Debugging -->
<bean parent="shibboleth.AdminFlow"
c:id="http://shibboleth.net/ns/profiles/resolvertest"
p:loggingId="%{idp.service.logging.resolvertest:ResolverTest}"
p:policyName="%{idp.resolvertest.accessPolicy:AccessByIPAddress}" />

<!-- REST StorageService Access -->
<bean parent="shibboleth.AdminFlow"
c:id="http://shibboleth.net/ns/profiles/storage"
p:loggingId="Storage"
p:policyName="AccessByIPAddress" />

<!-- REST Interface to Metrics -->
<bean parent="shibboleth.AdminFlow"
c:id="http://shibboleth.net/ns/profiles/metrics"
p:loggingId="Metrics"
p:policyNameLookupStrategy-ref="shibboleth.metrics.AccessPolicyStrategy" />

</util:list>

</beans>