{"id":24093268,"url":"https://github.com/umd-lib/reciprocal-borrowing-dev-env","last_synced_at":"2025-10-08T10:59:18.685Z","repository":{"id":195810532,"uuid":"693640458","full_name":"umd-lib/reciprocal-borrowing-dev-env","owner":"umd-lib","description":null,"archived":false,"fork":false,"pushed_at":"2023-09-20T12:00:00.000Z","size":127,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-01-10T09:26:23.242Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/umd-lib.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-09-19T12:29:47.000Z","updated_at":"2023-09-19T12:32:03.000Z","dependencies_parsed_at":"2023-09-19T17:58:52.132Z","dependency_job_id":"94b35ea7-d5a2-4b00-87b3-d7f750df9e81","html_url":"https://github.com/umd-lib/reciprocal-borrowing-dev-env","commit_stats":null,"previous_names":["umd-lib/reciprocal-borrowing-dev-env"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umd-lib%2Freciprocal-borrowing-dev-env","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umd-lib%2Freciprocal-borrowing-dev-env/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umd-lib%2Freciprocal-borrowing-dev-env/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umd-lib%2Freciprocal-borrowing-dev-env/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/umd-lib","download_url":"https://codeload.github.com/umd-lib/reciprocal-borrowing-dev-env/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241005380,"owners_count":19892780,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-10T09:26:52.385Z","updated_at":"2025-10-08T10:59:18.678Z","avatar_url":"https://github.com/umd-lib.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# reciprocal-borrowing-dev-env\n\nThis repository provides a local environment, via Docker, for developing and\ntesting the Reciprocal Borrowing application\n(\u003chttps://github.com/umd-lib/reciprocal-borrowing\u003e).\n\n## Provided Applications\n\nThis environment provides configured instances of the following applications:\n\n* OpenLDAP\n* Shibboleth Identity Provider (IdP)\n* Shibboleth Service Provider (SP)\n\n## Development Environment Setup\n\n### 1) Prerequisites\n\n1.1) Edit the “/etc/hosts” file on the local workstation:\n\n```zsh\nsudo vi /etc/hosts\n```\n\nand add the following entries:\n\n```text\n127.0.0.1       shib-idp\n127.0.0.1       borrow-local\n```\n\n### 2) Application Setup\n\n2.1) In a base directory, clone this repository:\n\n```zsh\n$ git clone git@github.com:umd-lib/reciprocal-borrowing-dev-env.git\n```\n\n2.2) In the same base directory, clone the \"reciprocal-borrowing\" repository:\n\n```zsh\n$ git clone git@github.com:umd-lib/reciprocal-borrowing.git\n```\n\n### 3) Running the Application\n\nThe following steps assume that a suitable Shibboleth SP Docker image has been\ncreated, containing a Ruby version compatible with the Reciprocal Borrowing\napplication being developed. See below for information about creating\na Shibboleth SP Docker image.\n\n3.1) Switch into the \"reciprocal-borrowing-dev-env\" directory:\n\n```zsh\n$ cd reciprocal-borrowing-dev-env\n```\n\n3.2) Start the Docker stack:\n\n```zsh\n$ docker compose up\n```\n\n3.3) Once the Docker stack has started, run a Bash shell in the \"borrow-local\"\ncontainer:\n\n```zsh\n$ docker exec -it borrow-local /bin/bash\n```\n\n3.4) In the \"borrow-local\" container, run the following commands to install the\ngems needed for the Reciprocal Borrowing application:\n\n```bash\nborrow-local$ cd /root/reciprocal-borrowing\nborrow-local$ bundle config set force_ruby_platform true\nborrow-local$ bundle config set --local path 'vendor/bundle'\nborrow-local$ bundle install\n```\n\n---\n**Note:** Installing the gems will take approximately 10-20 minutes, but are\nstored in the \"vendor\" directory of the Reciprocal Borrowing application, so\nthe gems will still be available after stopping and restarting tje Shibboleth SP\n\"borrow-local\"container.\n\nThe gems are configured to use the \"amd64\" architecture, and so are not\ndirectly usable on an M-series laptop, outside of the Docker container.\n\n---\n\n3.5) Access the application in a web browser by\ngoing to, go to:\n\n\u003chttps://borrow-local/\u003e\n\nThe browser may display a warning message related to unsigned certificates.\nAccept the self-signed certificate, and (after a few 10s of seconds) the\nReciprocal Borrowing home page will be shown.\n\n3.6) On the Reciprocal Borrowing home page, select one of the organizations as\nthe authenticating organization.\n\nAfter selecting the authenticating organization, the browser may display a\nwarning message related to unsigned certificates. Accept the self-signed\ncertificate, and the login page from the IdP will be shown.\n\n3.7) On the login page, enter the username and password, such as:\n\n* Username: `is_eligible`\n* Password: `password`\n\nand left-click the \"Login\" button. See the \"Custom Users\" section below for\nadditional users and credentials.\n\n3.8) The Reciprocal Borrowing result page will be shown indicating that the user\nis able to borrow.\n\nDevelopment can be done in the \"reciprocal-borrowing\" directory on the local\nworkstation. The file changes will be automatically copied into the Shibboleth\nSP Docker container.\n\n## Helpful Commands\n\nThe following commands can be run in the Shibboleth SP \"borrow-local\" Docker\ncontainer, which can be accessed by running:\n\n```zsh\n$ docker exec -it borrow-local /bin/bash\n```\n\n### Restart Apache\n\nTo restart Apache after making changes to the Apache configuration, run:\n\n```bash\nborrow-local$ supervisorctl restart httpd\n```\n\n### Restart Passenger/reciprocal-borrowing\n\nThe \"reciprocal-borrowing\" repository can be edited on the local machine, and\nthe changes will be automatically propagated to the Docker container and\nreflected in the running Rails application, as in normal Rails development.\n\nSome Rails changes, such as changes to the configuration or internationalization\nfiles require the Rails application to be restarted, which can be done by\nrunning the following command (in the \"borrow-local\" Docker container):\n\n```bash\nborrow-local$ passenger-config restart-app /root/reciprocal-borrowing\n```\n\n**Note:** Normal Rails development changes (i.e., changes to the application\nviews and controllers) should be picked up automatically (as if running in the\nlocal development environment).\n\n## Known Issues\n\nThe following are known issues with this “reciprocal-borrow-dev-env”\nimplementation:\n\n* The user identifying attributes from LDAP (“cn”, “sn”, “givenName”,\n  “displayName”) are not passed to the Rails application by the\n  Shibboleth SP. Therefore the “Name”, “Principal Name”, and “Identifier” on\n  the Reciprocal Borrowing result page will all display “N/A”.\n\n* The Apache in the “borrow-local” Shibboleth SP container runs as “root”, and\n  hence the Phusion Passenger and “reciprocal-borrowing” application also run as\n  “root”. This is perfectly fine for a local development setup, but it likely\n  not ideal for a production deployment (which this repository is not intended\n  to provide).\n\n## Shibboleth SP Docker Image Setup\n\nThe \"sp\" subdirectory contains a snapshot of the\n\"3.4.1_06122023_rocky8_multiarch\" branch of the  Shibboleth SP Docker image\nsetup configuration\n(\u003chttps://github.internet2.edu/docker/shib-sp/tree/3.4.1_06122023_rocky8_multiarch\u003e)\n\nThe \"Dockerfile\" from the snapshot has been modified to include Ruby and the\nPhusion Passenger web application server.\n\nThe \"docker-compose.yml\" file has been modified to mount the local\n\"reciprocal-borrowing\" directory into the container to enable local development.\n\nThe Shibboleth SP Docker image should be recreated whenever:\n\n* The Ruby version used by the \"reciprocal-borrowing\" application is updated\n* As needed, to keep up with any Shibboleth SP or Phusion Passenger version\n  changes used in production.\n\nThe following instructions use that the Kubernetes \"build\" environment to\nconstruct an \"amd64\" Docker image (which is currently necessary, as Phusion\nPassenger does not have an \"arm64\" build).\n\nFor more information about setting up the Kubernetes \"build\" environment, see\n\u003chttps://github.com/umd-lib/k8s/blob/main/docs/DockerBuilds.md\u003e in Confluence.\n\n1) Switch into the \"reciprocal-borrowing-dev-env\" directory:\n\n```zsh\n$ cd reciprocal-borrowing-dev-env\n```\n\n2) Run the following command to build the \"shib-sp-reciprocal-borrowing:\\\u003cTAG\u003e\"\n   Docker image where \\\u003cTAG\u003e is the Docker image tag to create:\n\n```zsh\n$ docker buildx build --no-cache --progress=plain --builder kube  --load \\\n  --platform linux/amd64 -f sp/Dockerfile \\\n  -t docker.lib.umd.edu/shib-sp-reciprocal-borrowing:\u003cTAG\u003e sp/.\n```\n\nFor example, if the \\\u003cTAG\u003e is \"ruby-3.2.2\" than the command would be:\n\n```zsh\n$ docker buildx build --no-cache --progress=plain --builder kube  --load \\\n  --platform linux/amd64 -f sp/Dockerfile \\\n  -t docker.lib.umd.edu/shib-sp-reciprocal-borrowing:ruby-3.2.2 sp/.\n```\n\nThis build takes approximately 10 minutes. The \"--load\" flag is used to ensure\nthat the resulting \"shib-sp-reciprocal-borrowing\" Docker image is loaded on the\nlocal workstation, and *not* pushed to the Nexus.\n\n---\n**Note:** The version of Phusion Passenger is not \"pinned\" and is installed\nvia the \"yum\" package manager, so its version may differ over time. The\ncurrent Dockerfile configuration was derived from the instructions at\n\u003chttps://www.phusionpassenger.com/docs/advanced_guides/install_and_upgrade/apache/install/oss/el8.html\u003e.\n\nThe current recommendation is to label the Docker image using the Ruby version,\nas that is the most likely reason for updating the Docker image.\n\n---\n\n3) After creating the Docker image, update the \"borrow-local\" container in the\n   \"docker-compose.yml\" file to use the new image.\n\n4) Test the image by running the Docker Compose stack. If everything is working,\n   push the Docker image to the Nexus, using the following command\n   (where \\\u003cTAG\u003e) is the tag of the Docker image:\n\n```zsh\n$ docker push docker.lib.umd.edu/shib-sp-reciprocal-borrowing:\u003cTAG\u003e\n```\n\nFor example, if the \\\u003cTAG\u003e is \"ruby-3.2.2\", then the command would be:\n\n```zsh\n$ docker push docker.lib.umd.edu/shib-sp-reciprocal-borrowing:ruby-3.2.2\n```\n\n## Docker Compose\n\nThe applications are set up using Docker Compose.\n\nAll application run on a Docker \"reciprocal-borrowing-network\" internal network.\n\n## OpenLDAP\n\nThe OpenLDAP implementation uses a stock \"bitnami/openldap\" Docker image\n(\u003chttps://hub.docker.com/r/bitnami/openldap\u003e) pulled from Docker Hub.\n\nThe OpenLDAP server runs on ports 1389 and 1636, and is available using the\n\"openldap\" hostname.\n\n### Authentication Credentials\n\nThe following authentication credentials are used to connect to the\nOpenLDAP server:\n\n| Username   | Password       |\n| ---------- | -------------- |\n| adminuser  | adminpassword  |\n\n### Custom Users\n\nThe OpenLdap instance reads in the LDIF files in the \"ldap/ldif\" directory.\n\nThe following users are available:\n\n| Username      | Password | Note                                        |\n| ------------- | -------- | ------------------------------------------- |\n| is_eligible   | password | This user is eligible for borrowing         |\n| not_eligible  | password | This user is **not** eligible for borrowing |\n\n### LDIF Files\n\nThe LDIF files in the \"ldap/ldifs\" directory provide the initial setup of the\nOpenLDAP database. These files are only read the first time OpenLDAP starts.\n\nTo reset the OpenLDAP database from the LDIF files:\n\n1) Stop Docker Compose:\n\n```zsh\n$ docker compose down\n```\n\n2) Delete the \"reciprocal-borrowing-dev-env_openldap_data\" Docker volume:\n\n```zsh\n$ docker volume rm reciprocal-borrowing-dev-env_openldap_data\n```\n\n3) Restart Docker Compose:\n\n```zsh\n$ docker compose up\n```\n\n### OpenLDAP Verification\n\nVerification that OpenLDAP is running can be done by running the following\ncommand:\n\n```zsh\n$ ldapsearch -D \"cn=admin,dc=example,dc=org\" -W -p 1389 -h 127.0.0.1 -b \"dc=example,dc=org\" -s sub -x \"(objectclass=*)\"\n```\n\nWhen prompted, the password is `adminpassword`\n\n## Shibboleth Identity Provider (IdP)\n\nThe Shibboleth Identity Provider (IdP) connects to the OpenLDAP server to\nauthenticate users and retrieve user attributes.\n\nThe IdP implementation uses the TIER Shibboleth IdP Docker Reference\nimplementation (see\n\u003chttps://spaces.at.internet2.edu/display/TPWG/TIER+Shibboleth+IdP+-+Docker+Reference+Implementation\u003e)\nwith additional information available at\n\u003chttps://docs.google.com/document/d/17-0O3Tvty9PONL6wu4PiC6ZWramdyntXmOsq1UpD2tE/edit\u003e.\n\nThe IdP Docker image in built as part of the Docker Compose start up, utilizing\nthe configuration files present in the \"idp\" subdirectory.\n\n### IdP Dockerfile and Configuration\n\nThe contents of the \"idp\" subdirectory were initially created using the\n\"tier/shibbidp_configbuilder_container\" Docker image:\n\n```zsh\n$ docker run --interactive --tty -v $PWD:/output -e \"BUILD_ENV=LINUX\" tier/shibbidp_configbuilder_container\n\nEnter the FQDN or IP address of your server: shib-idp\nEnter the Scope for your IdP [shib-idp]: shib-idp\n\nEnter the LDAP URL used for your IdP: ldap://openldap:1389\n\nEnter the LDAP Base DN used for your LDAP Server: dc=example,dc=org\n\nEnter the LDAP DN for the service account used by your IdP: cn=admin,dc=example,dc=org\nEnter the password for the account just specified: adminpassword\n```\n\n### IdP File Modifications\n\nThe following files were modified to support the configuration expected by\nReciprocal Borrowing. The original version of the files have a \".dist\"\nextension.\n\nAfter modifying any of the IdP configuration files, delete the existing\n\"reciprocal-borrowing-dev-env-shib-idp\" Docker image, to have the IdP\nautomatically rebuilt with the changes:\n\n```zsh\n$ docker image rm reciprocal-borrowing-dev-env-shib-idp\n```\n\n#### idp/config/shib-idp/conf/access-control.xml\n\nThe IP Address CIDR '0.0.0.0/0' was added to the \"AccessByIPAddress\"\nstanza, to allow connections from any IPv4 address.\n\n#### idp/config/shib-idp/conf/attribute-filter.xml\n\nAdded a \"reciprocal_borrowing_filter\" AttributeFilterPolicy that only releases\nthe \"eduPersonEntitlement\" attribute for the \"is_eligible\" user.\n\n#### idp/config/shib-idp/conf/attribute-resolver.xml\n\nModified to supply \"eduPersonEntitlement\" attribute as a static attribute,\ninstead of from LDAP.\n\nAn \"eduPersonEntitlement\" attribute with a value of\n`https://borrow.btaa.org/reciprocalborrower` indicates that a user is eligible\nto borrow.\n\nThe \"reciprocal_borrowing_filter\" AttributeFilterPolicy in\n\"idp/config/shib-idp/conf/attribute-filter.xml\" only releases the attribute for\nthe \"is_eligible\" user.\n\n#### idp/config/shib-idp/metadata/idp-metadata.xml\n\nModified the IDP service endpoints to use port 1443.\n\n#### idp/config/shib-idp/conf/ldap.properties\n\nModified to support connecting to the OpenLDAP container, and to reflect the\nuser attributes produced by LDAP.\n\n#### idp/config/shib-idp/conf/metadata-providers.xml\n\nModified to look up metadata provider from the\n\"/opt/shibboleth-idp/conf/borrow-local.xml\" file.\n\nThe \"borrow-local.xml\" file is generated by the Shibboleth SP (see below).\n\n### IdP Verification\n\nIn a web browser go to\n\n\u003chttps://shib-idp:1443/idp/profile/admin/hello\u003e\n\nShould be able to login using `is_eligible` with a password of `password`.\n\n## Shibboleth Service Provider (SP)/Reciprocal Borrowing\n\n## SP Dockerfile and Configuration\n\nThe contents of the \"sp\" directory were generated from the\n\"3.4.1_06122023_rocky8_multiarch\" branch of the\n\u003chttps://github.internet2.edu/docker/shib-sp.git\u003e Git repository,\nspecifically Git hash\n\"[1b51145b510b11380702c36d7b163a1b9dfbca3f](https://github.internet2.edu/docker/shib-sp/commit/1b51145b510b11380702c36d7b163a1b9dfbca3f)\".\n\nThe \".git\" subdirectory was then deleted.\n\n```zsh\n$ git clone https://github.internet2.edu/docker/shib-sp.git sp\n$ cd sp\n$ git checkout 3.4.1_06122023_rocky8_multiarch\n$ rm -rf .git\n```\n\n## Generating the SP certificates and metadata\n\nThe IdP requires metadata identifying the SP that uses self-signed certificates\ngenerated as part of the SP Docker container startup.\n\nIn the normal configuration, these certificates are rebuilt every time the\nSP Docker image is built.\n\nTo simplify the setup of this environment, the SP Dockerfile was modified\nto use fixed \"sp-encrypt-key.pem\" and \"sp-encrypt-cert.pem\" files.\n\n### SP File Modifications\n\nThe following files were modified to support the configuration expected by\nReciprocal Borrowing. The original version of the files have a \".dist\"\nextension.\n\n#### sp/Dockerfile\n\nA section was appended to the end of the stock Dockerfile to install\nPhusion Passenger and Ruby.\n\n#### sp/container_files/shibboleth/attribute-map.xml\n\nModified to return the \"eduPersonEntitlement\" as \"eduPersonEntitlement\",\ninstead of as \"entitlement\".\n\nThe \"eduPersonEntitlement\" key is what is used by Reciprocal Borrowing to\nidentify users authorized to borrow.\n\n#### sp/container_files/shibboleth2.xml\n\nThis added file configures the SP to talk to the IdP. The original file\n(as renamed to \"shibboleth2.xml.dist\") was generated by building and running the\n\"sp/Dockerfile\" without a \"shibboleth2.xml\" file once, and then copying the\nfile in the \"/etc/shibboleth/\" directory.\n\n#### sp/container_files/httpd/00-virtualhosts.conf\n\nModified the Apache/Phusion Passenger configuration to use the\n\"development_docker\" Rails environment, and to enable the \"Reciprocal Borrowing\"\napplication to be placed in the \"/root\" directory of the SP container.\n\n#### Self-signed certificate files\n\nThe following self-signed certificates files were generated in an initial run of\nthe stock SP Docker image, and then copied from the running Docker container:\n\n* sp-encrypt-cert.pem\n* sp-encrypt-key.pem\n* sp-signing-cert.pem\n* sp-signing-key.pem\n\nThe SP Dockerfile has been modified to use these files, in place of regenerating\nthe certificates on each build. This enables the metadata file provided to the\nIdP to remain unchanged.\n\nTo regenerate these files (which should not be necessary):\n\n1) Delete the existing \"sp-*-cert.pem\" files:\n\n```zsh\n$ cd reciprocal-borrowing-dev-env\n$ rm sp/container_files/shibboleth/sp-encrypt-cert.pem\n$ rm sp/container_files/shibboleth/sp-encrypt-key.pem\n$ rm sp/container_files/shibboleth/sp-signing-cert.pem\n```\n\n2) Rebuild the \"shib-sp-reciprocal-borrowing\" Docker image:\n\n```zsh\n$ docker buildx build --no-cache --progress=plain --builder kube  --load \\\n  --platform linux/amd64 -f sp/Dockerfile \\\n  -t shib-sp-reciprocal-borrowing:latest sp/.\n```\n\n**Note:** The resulting image should *not* be pushed to the Nexus.\n\n3) Run the \"shib-sp-reciprocal-borrowing\" Docker image:\n\n```zsh\n$ docker run --rm --publish=443:443 --name borrow-local shib-sp-reciprocal-borrowing:latest\n```\n\n4) Retrieve the Shibboleth SP metadata and copy into the \"idp\" directory, so\n   that it available to the IdP:\n\n```zsh\n$ curl --insecure https://borrow-local/Shibboleth.sso/Metadata \u003e idp/config/shib-idp/conf/shib-sp.xml\n```\n\n5) Copy the following files into the \"sp\" directory, so that they will be used\n   by the SP:\n\n```zsh\n$ docker cp borrow-local:/etc/shibboleth/sp-encrypt-cert.pem sp/container_files/shibboleth/\n$ docker cp borrow-local:/etc/shibboleth/sp-encrypt-key.pem sp/container_files/shibboleth/\n$ docker cp borrow-local:/etc/shibboleth/sp-signing-cert.pem sp/container_files/shibboleth/\n$ docker cp borrow-local:/etc/shibboleth/sp-signing-key.pem sp/container_files/shibboleth/\n```\n\n6) Stop the \"borrow-local\" Docker container.\n\n7) If necessary, delete the existing IdP Docker image:\n\n```zsh\n$ docker image rm reciprocal-borrowing-dev-env-shib-idp\n```\n\n8) Rebuild the Shibboleth SP Docker image using the instructions in the\n   \"Shibboleth SP Docker Image Setup\" section above, and push to the Nexus.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fumd-lib%2Freciprocal-borrowing-dev-env","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fumd-lib%2Freciprocal-borrowing-dev-env","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fumd-lib%2Freciprocal-borrowing-dev-env/lists"}