├── .gitignore ├── LICENSE ├── README.md ├── api-exercise.R ├── australia-elex-2016 ├── Notebook.Rmd └── australia-elex-2016.Rproj ├── docker ├── README.md ├── demo-mariadb │ ├── Dockerfile │ └── files │ │ └── init.sql ├── docker-compose.yaml ├── generate-certs.sh ├── openldap-password.env ├── rr-example │ └── Dockerfile ├── rstudio-compose.yaml ├── rstudio-lubridate │ └── Dockerfile ├── shiny-apache-shib-sp │ ├── Dockerfile │ └── files │ │ ├── attribute-map.xml │ │ ├── proxy.conf │ │ ├── saml-metadata.xml │ │ ├── shib.conf │ │ ├── shibboleth2.xml │ │ ├── sp-cert.pem │ │ └── sp-key.pem ├── shiny-idp │ ├── Dockerfile │ └── files │ │ ├── access-control.xml │ │ ├── attribute-filter.xml │ │ ├── attribute-resolver.xml │ │ ├── idp-signing-cert.pem │ │ ├── idp-signing-key.pem │ │ ├── idp.properties │ │ ├── ldap.properties │ │ ├── login.vm │ │ ├── metadata-providers.xml │ │ ├── relying-party.xml │ │ └── saml-metadata.xml ├── shiny-openldap │ ├── Dockerfile │ └── files │ │ ├── 0110_ous.ldif │ │ └── 9001_testusers.ldif ├── shiny-tomcat8-proxied │ ├── Dockerfile │ └── files │ │ ├── catalina.properties │ │ ├── catalina.sh │ │ └── server.xml ├── shiny │ ├── Dockerfile │ └── files │ │ ├── db-access-secure │ │ └── app.R │ │ ├── db-access │ │ └── app.R │ │ ├── header-whitelist.js │ │ ├── hostinfo │ │ └── app.R │ │ ├── saml │ │ └── app.R │ │ └── shiny-server.conf └── tidyverse-mariadb │ └── Dockerfile └── shiny-app └── shiny ├── db-access-secure └── app.R ├── db-access └── app.R ├── example-assertion.xml ├── hostinfo └── app.R ├── saml └── app.R └── shiny.Rproj /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | *.nb.html 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Shiny Docker Demo 2 | 3 | This repository contains a demonstration of how to host a [Shiny](https://shiny.rstudio.com/) app in [Docker](https://www.docker.com/). 4 | 5 | The `docker` directory contains Dockerfiles and contexts for a set of images necessary for the demonstration. There are also 6 | compose files for a couple of demonstration scenarios. 7 | 8 | The `shiny-app` directory contains an RStudio project and several Shiny apps to demonstrate various features. 9 | 10 | The `australia-elex-2016` directory contains an RStudio project that performs some basic analysis on data from the 2016 Federal election in Australia. It serves 11 | as a demo of using Docker to support [reproducible research](http://ropensci.github.io/reproducibility-guide/sections/introduction/). 12 | 13 | The original setting for this demonstration was a tutorial at the [useR! 2018 Conference](https://user2018.r-project.org/). I will continue 14 | evolving the demonstration as new Docker features become available, and based on feedback/PRs from tutorial attendees and others. 15 | -------------------------------------------------------------------------------- /api-exercise.R: -------------------------------------------------------------------------------- 1 | # docker run -it --rm --mount "type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock" -e COLUMNS=250 rocker/tidyverse:3.5.0 R 2 | 3 | options(width=Sys.getenv('COLUMNS')) 4 | 5 | library(jsonlite) 6 | library(httr) 7 | library(tidyverse) 8 | 9 | GET('http://localhost/images/json', config(unix_socket_path='/var/run/docker.sock')) %>% 10 | .$content %>% 11 | rawToChar() %>% 12 | fromJSON() %>% 13 | select(-Labels) %>% 14 | as_tibble() %>% 15 | unnest(RepoTags) %>% 16 | filter(grepl(x=RepoTags, pattern='shiny')) 17 | -------------------------------------------------------------------------------- /australia-elex-2016/Notebook.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Analysis of Australia's 2016 Federal Election" 3 | output: html_notebook 4 | --- 5 | 6 | ```{r, echo=FALSE} 7 | suppressMessages(library(tidyverse, quietly=TRUE)) 8 | suppressMessages(suppressWarnings(library(rgeos, quietly = TRUE))) 9 | suppressMessages(suppressWarnings(library(rgdal, quietly = TRUE))) 10 | library(broom) 11 | library(ggthemes) 12 | suppressMessages(suppressWarnings(library(scales))) 13 | ``` 14 | 15 | This notebook presents a very basic analysis of results from the Australian Federal election in 2016 for the House of Representatives. The intent here is to provide an example of using Docker to support reproducible research rather than a comprehensive analysis of the election. 16 | 17 | Data sources included: 18 | 19 | * Vote tallies from the [Australian Electoral Commission (AEC)](https://results.aec.gov.au/20499/Website/HouseDownloadsMenu-20499-Csv.htm) 20 | * Census estimates by Commonwealth Electoral District from the [Australian Bureau of Statistics](http://www.abs.gov.au/websitedbs/censushome.nsf/home/tablebuilder) 21 | * Electoral district shapefile from the AEC at https://www.aec.gov.au/Electorates/gis/gis_datadownload.htm 22 | 23 | R was used to transform the data from these sources into a [data.world dataset](https://data.world/scottcame/australian-federal-election-2016). The R source code for the transformation is [here](https://github.com/scottcame/elections-data/blob/master/australia-elections/AustraliaElection.R). 24 | 25 | ```{r, echo=FALSE, message=FALSE} 26 | 27 | ElectionResults2016 <- suppressMessages(read_csv('https://query.data.world/s/rdtdjo6gianfc64voj3pbnfpdueadv')) %>% 28 | inner_join(suppressMessages(read_csv('https://query.data.world/s/odgvs4f5uy66gg5hrovs6jct5mdx26')), by='CED') %>% 29 | mutate(LiberalCoalitionVotes=LP+LNP+NP, LiberalCoalitionPct=LiberalCoalitionVotes/Turnout) %>% 30 | mutate(UnemploymentRate=(LabourForceStatus_Unemployed_looking_for_FT+LabourForceStatus_Unemployed_looking_for_PT) / 31 | (LabourForceStatus_Unemployed_looking_for_FT+LabourForceStatus_Unemployed_looking_for_PT+ 32 | LabourForceStatus_Employed_worked_FT+LabourForceStatus_Employed_worked_PT+LabourForceStatus_Employed_away_from_work)) 33 | 34 | #ElectionResults2016Flat <- ElectionResults2016 %>% select(-Enrolment, -Turnout, -WinningParty) %>% gather('Party', 'Votes', -CED, -DivisionID, -State) 35 | Parties2016 <- suppressMessages(read_csv('https://query.data.world/s/u52ol56qmsvldxxkmrtzrno345pc4m')) 36 | 37 | nationalShp <- tempfile() 38 | download.file('https://www.aec.gov.au/Electorates/gis/files/national-midmif-09052016.zip', nationalShp, quiet=TRUE) 39 | nationalShpDir <- tempdir() 40 | unzip(nationalShp, exdir = nationalShpDir) 41 | nationalShp <- readOGR(file.path(nationalShpDir, 'COM_ELB.TAB'), layer="COM_ELB", stringsAsFactors = FALSE, verbose=FALSE) 42 | 43 | nationalShpData <- nationalShp@data 44 | nationalShpData$id <- rownames(nationalShpData) 45 | 46 | nationalShpData <- nationalShpData %>% 47 | mutate(Elect_div=case_when( 48 | Elect_div=='Mcpherson' ~ 'McPherson', 49 | Elect_div=='Mcmillan' ~ 'McMillan', 50 | TRUE ~ Elect_div 51 | )) 52 | 53 | nationalShp <- nationalShp %>% SpatialPolygonsDataFrame(nationalShpData) %>% 54 | gSimplify(.01) 55 | 56 | results <- ElectionResults2016 %>% select(CED, LiberalCoalitionPct) %>% inner_join(nationalShpData, by=c('CED'='Elect_div')) 57 | 58 | nationalSPDF <- suppressMessages(tidy(nationalShp)) %>% 59 | left_join(results, by='id') 60 | 61 | ``` 62 | 63 | #### National Results Map 64 | 65 | The following shows the percentage of votes in each electoral district won by the Liberal / National Liberal Party of Queensland / Nationals coalition that formed the government following the election: 66 | 67 | ```{r, echo=FALSE, fig.width=6} 68 | nationalSPDF %>% ggplot(aes(x=long, y=lat, group=group, fill=LiberalCoalitionPct)) + 69 | geom_polygon() + 70 | scale_fill_continuous(label=percent) + 71 | coord_map() + theme_map() + labs(title='Liberal Coalition Vote Share', subtitle='By Electoral District, 2016 Federal Election for House of Representatives', 72 | fill='Liberal Coalition Vote Share') 73 | ``` 74 | 75 | #### Unemployment Rate and Liberal Coalition Vote Share 76 | 77 | One might hypothesize that voters in electoral districts with higher unemployment might be disinclined to support the incumbent Liberal coalition parties. This scatterplot, using 2016 Census results, lends some support to this hypothesis by showing that as unemployment rate increases in an electoral district, support for the Liberals declines: 78 | 79 | ```{r, echo=FALSE, fig.width=6} 80 | ggplot(ElectionResults2016, aes(x=UnemploymentRate, y=LiberalCoalitionPct)) + geom_point() + geom_smooth(method='lm') + 81 | scale_y_continuous(labels=percent) + scale_x_continuous(labels=percent) + 82 | labs(title='Correlation of Unemployment Rate and Liberal Coalition Vote Share', subtitle='By Electoral District, 2016 Federal Election for Australia House of Representatives', 83 | x='Unemployment Rate (2016 Census)', y='Liberal Coalition Vote Share') 84 | ``` 85 | -------------------------------------------------------------------------------- /australia-elex-2016/australia-elex-2016.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | ### Docker Images 2 | 3 | This directory contains the Dockerfiles and associated contexts for building images that are part of the demonstration. The images are: 4 | 5 | * *demo-mariadb:* A small [MariaDB](https://mariadb.org/) database pre-loaded with some simple demo data used in Shiny apps 6 | * *shiny-apache-shib-sp:* An [Apache web/proxy server](https://httpd.apache.org/) configured with the [Shibboleth Service Provider](https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPGettingStarted) to gate access to services and proxy http traffic 7 | * *shiny-idp:* A [Shibboleth Identity Provider](https://wiki.shibboleth.net/confluence/display/IDP30/Home) to respond to SAML authentication requests and form/share assertions with the Service Provider (and, indirectly, with backend apps) 8 | * *shiny-openldap:* An [Open LDAP server](https://www.openldap.org/) to store and manage user authentication credentials and user attributes, which form the basis of assertions made by the Identity Provider and relied upon (and trusted) by the Service Provider and backend apps 9 | * *shiny-tomcat8-proxied:* A [Tomcat J2EE Servlet Container](http://tomcat.apache.org/) used to host the Identity Provider (and is available for easily hosting any other Java Web Application) 10 | * *shiny:* A [Shiny Server](https://shiny.rstudio.com/) instance, tweaked to pass through http headers added by Shibboleth, that will host Shiny apps for the demonstration 11 | * *tidyverse-mariadb:* A derived image from the [Rocker project's](https://github.com/rocker-org/rocker) [tidyverse](https://hub.docker.com/r/rocker/tidyverse/) image, extended to include the [RMariaDB package](https://cran.r-project.org/web/packages/RMariaDB/index.html) and system libraries on which the package depends 12 | 13 | Note that all of these images are maintained in Docker Hub on my [site](https://hub.docker.com/u/scottcame/). 14 | 15 | This directory also contains two [Docker Compose](https://docs.docker.com/compose/) files: one that orchestrates the Shiny demo, and the other that runs an instance of RStudio Server in a container along with the demo MariaDB. 16 | -------------------------------------------------------------------------------- /docker/demo-mariadb/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mariadb 2 | 3 | LABEL maintainer="Scott Came (scottcame10@gmail.com)" \ 4 | org.label-schema.description="Image with MariaDB instance containing demo data for Shiny demo" \ 5 | org.label-schema.vcs-url="https://github.com/scottcame/shiny-microservice-demo/docker/demo-mariadb" 6 | 7 | ENV MYSQL_ALLOW_EMPTY_PASSWORD=yes 8 | 9 | COPY files/* /docker-entrypoint-initdb.d/ 10 | -------------------------------------------------------------------------------- /docker/demo-mariadb/files/init.sql: -------------------------------------------------------------------------------- 1 | GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'; 2 | 3 | create database demo1; 4 | 5 | use demo1; 6 | 7 | create table t1A (pk int primary key, v varchar(20)); 8 | insert into t1A values(1, 'Table A Row One'); 9 | insert into t1A values(2, 'Table A Row Two'); 10 | insert into t1A values(3, 'Table A Row Three'); 11 | insert into t1A values(4, 'Table A Row Four'); 12 | 13 | create table t1B (pk int primary key, v varchar(20)); 14 | insert into t1B values(1, 'Table B Row One'); 15 | insert into t1B values(2, 'Table B Row Two'); 16 | insert into t1B values(3, 'Table B Row Three'); 17 | insert into t1B values(4, 'Table B Row Four'); 18 | -------------------------------------------------------------------------------- /docker/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | # compose file that defines services established as docker daemon startup containers 2 | # run with: docker-compose up -d 3 | 4 | version: "3" 5 | 6 | networks: 7 | shiny-demo: 8 | driver: bridge 9 | ipam: 10 | driver: default 11 | config: 12 | - subnet: 172.22.0.0/16 13 | 14 | services: 15 | shiny-openldap: 16 | image: scottcame/shiny-openldap 17 | container_name: shiny-openldap 18 | networks: 19 | - "shiny-demo" 20 | # remove ports directive in production, to avoid exposure of the ldap directory to the outside 21 | ports: 22 | - "1389:389" 23 | env_file: 24 | - ./openldap-password.env 25 | environment: 26 | - SLAPD_DOMAIN=ldap.localhost.localdomain 27 | shiny-idp: 28 | image: scottcame/shiny-idp 29 | container_name: shiny-idp 30 | networks: 31 | - "shiny-demo" 32 | depends_on: 33 | - shiny-openldap 34 | shiny-apache-shib-sp: 35 | image: scottcame/shiny-apache-shib-sp 36 | container_name: shiny-apache-shib-sp 37 | networks: 38 | - "shiny-demo" 39 | ports: 40 | - "80:80" 41 | - "443:443" 42 | shiny: 43 | image: scottcame/shiny 44 | container_name: shiny 45 | networks: 46 | - "shiny-demo" 47 | ports: 48 | - "3838:3838" 49 | demo-mariadb: 50 | image: scottcame/demo-mariadb 51 | container_name: demo-mariadb 52 | networks: 53 | - "shiny-demo" 54 | ports: 55 | - "13306:3306" 56 | -------------------------------------------------------------------------------- /docker/generate-certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # typically you'll only need to do this if you want to refresh the certs...not needed after initial generation, even for subsequent builds 4 | # including this script mostly to document how we generated the certs in the first place 5 | 6 | # borrowed liberally from https://wiki.shibboleth.net/confluence/display/CONCEPT/SAMLKeysAndCertificates#SAMLKeysAndCertificates-CreatingaSAMLKeyandCertificate 7 | 8 | # Service Provider cert/key 9 | openssl req -new -x509 -nodes -newkey rsa:2048 -keyout shiny-apache-shib-sp/files/sp-key.pem -days 7300 -out shiny-apache-shib-sp/files/sp-cert.pem -subj "/C=US/ST=WA/L=Olympia/O=Cascadia Analytics/CN=localhost.localdomain/emailAddress=docker@localhost" 10 | 11 | # Identity Provider cert/key 12 | openssl req -new -x509 -nodes -newkey rsa:2048 -keyout shiny-idp/files/idp-signing-key.pem -days 7300 -out shiny-idp/files/idp-signing-cert.pem -subj "/C=US/ST=WA/L=Olympia/O=Cascadia Analytics/CN=localhost.localdomain/emailAddress=docker@localhost" 13 | -------------------------------------------------------------------------------- /docker/openldap-password.env: -------------------------------------------------------------------------------- 1 | SLAPD_PASSWORD=password 2 | -------------------------------------------------------------------------------- /docker/rr-example/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rocker/geospatial:3.5.0 2 | 3 | VOLUME /output 4 | 5 | RUN apt-get update && apt-get install -y curl 6 | RUN R -e 'install.packages(c("ggthemes"))' 7 | RUN cd /tmp && curl -O https://raw.githubusercontent.com/scottcame/shiny-docker-demo/master/australia-elex-2016/Notebook.Rmd 8 | 9 | CMD ["R", "-e", "rmarkdown::render('/tmp/Notebook.Rmd', output_file='/output/Notebook.html')"] 10 | -------------------------------------------------------------------------------- /docker/rstudio-compose.yaml: -------------------------------------------------------------------------------- 1 | # A Minimal Docker Compose Example 2 | 3 | version: "3.5" 4 | 5 | networks: 6 | nw-useR: 7 | name: nw-useR 8 | 9 | services: 10 | rstudio: 11 | image: scottcame/tidyverse-mariadb 12 | container_name: rstudio 13 | networks: 14 | - nw-useR 15 | ports: 16 | - 8787:8787 17 | mariadb: 18 | image: scottcame/demo-mariadb 19 | container_name: demo-mariadb 20 | networks: 21 | - nw-useR 22 | -------------------------------------------------------------------------------- /docker/rstudio-lubridate/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rocker/rstudio 2 | 3 | RUN R -e 'install.packages("lubridate")' 4 | -------------------------------------------------------------------------------- /docker/shiny-apache-shib-sp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM frolvlad/alpine-glibc:alpine-3.7 2 | 3 | LABEL maintainer="Scott Came (scottcame10@gmail.com)" \ 4 | org.label-schema.description="Image containing Apache with mod proxy and mod shib to support shiny demo" \ 5 | org.label-schema.vcs-url="https://github.com/scottcame/shiny-microservice-demo/docker/shiny-apache-shib-sp" 6 | 7 | RUN apk add --update bash apache2 apache2-ssl apache2-proxy apache2-dev apache2-ctl alpine-sdk openssl libressl-dev boost-dev curl-dev bzip2-dev zlib-dev 8 | 9 | # This loosely follows the steps documented at https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPLinuxSourceBuild 10 | 11 | WORKDIR /tmp 12 | 13 | # Install log4shib 14 | 15 | RUN wget http://shibboleth.net/downloads/log4shib/latest/log4shib-1.0.9.tar.gz && \ 16 | tar -xvf log4shib-1.0.9.tar.gz && \ 17 | cd log4shib-1.0.9 && \ 18 | ./configure --disable-static --disable-doxygen --prefix=/opt/shibboleth-sp CXXFLAGS="-std=c++11" && \ 19 | make && \ 20 | make install && \ 21 | cd .. && rm -rf log4shib* 22 | 23 | # Install XercesC 24 | 25 | RUN wget http://archive.apache.org/dist/xerces/c/3/sources/xerces-c-3.1.2.tar.gz && \ 26 | tar -xvf xerces-c-3.1.2.tar.gz && \ 27 | cd xerces-c-3.1.2 && \ 28 | ./configure --prefix=/opt/shibboleth-sp --disable-netaccessor-libcurl && \ 29 | make && \ 30 | make install && \ 31 | cd .. && rm -rf xerces-c* 32 | 33 | # Install XML Security 34 | # Note we have to apply a "patch" to get this to compile with GCC v6+ 35 | # See https://issues.apache.org/jira/browse/SANTUARIO-437 36 | 37 | RUN wget http://www.apache.org/dist/santuario/c-library/xml-security-c-1.7.3.tar.gz && \ 38 | tar -xvf xml-security-c-1.7.3.tar.gz && \ 39 | cd xml-security-c-1.7.3 && \ 40 | sed -i -e "648s/false/NULL/" xsec/tools/checksig/InteropResolver.cpp && \ 41 | ./configure --without-xalan --disable-static --prefix=/opt/shibboleth-sp --with-xerces=/opt/shibboleth-sp CXXFLAGS="-w" && \ 42 | make && \ 43 | make install && \ 44 | cd .. && rm -rf xml-sec* 45 | 46 | # Install OpenSAML XML Tooling 47 | 48 | RUN wget http://shibboleth.net/downloads/c++-opensaml/latest/xmltooling-1.6.4.tar.gz && \ 49 | tar -xvf xmltooling-1.6.4.tar.gz && \ 50 | cd xmltooling-1.6.4 && \ 51 | ./configure --with-log4shib=/opt/shibboleth-sp --prefix=/opt/shibboleth-sp -C CXXFLAGS="-w" && \ 52 | make && \ 53 | make install && \ 54 | cd .. && rm -rf xmltooling* 55 | 56 | # Install OpenSAML 57 | 58 | RUN wget http://shibboleth.net/downloads/c++-opensaml/latest/opensaml-2.6.1.tar.gz && \ 59 | tar -xvf opensaml-2.6.1.tar.gz && \ 60 | cd opensaml-2.6.1 && \ 61 | ./configure --with-log4shib=/opt/shibboleth-sp --prefix=/opt/shibboleth-sp -C CXXFLAGS="-w" && \ 62 | make && \ 63 | make install && \ 64 | cd .. && rm -rf opensaml* 65 | 66 | # Install Shib daemon 67 | 68 | RUN wget http://shibboleth.net/downloads/service-provider/2.6.1/shibboleth-sp-2.6.1.tar.gz && \ 69 | tar -xvf shibboleth-sp-2.6.1.tar.gz && \ 70 | cd shibboleth-sp-2.6.1 && \ 71 | ./configure --with-log4shib=/opt/shibboleth-sp --prefix=/opt/shibboleth-sp --enable-apache-24 --with-apxs24=/usr/bin/apxs CXXFLAGS="-w" && \ 72 | make && \ 73 | make install && \ 74 | cd .. && rm -rf shibboleth* && \ 75 | apk del apache2-dev 76 | 77 | # Copy config files over and do some editing 78 | 79 | # Make startup script 80 | 81 | RUN echo '#!/bin/bash' > /opt/shibboleth-sp/sbin/start-shib-and-apache && \ 82 | echo "/opt/shibboleth-sp/sbin/shibd -f" >> /opt/shibboleth-sp/sbin/start-shib-and-apache && \ 83 | echo "mkdir -p /run/apache2" >> /opt/shibboleth-sp/sbin/start-shib-and-apache && \ 84 | echo "apachectl start -DFOREGROUND" >> /opt/shibboleth-sp/sbin/start-shib-and-apache && \ 85 | chmod u+x /opt/shibboleth-sp/sbin/start-shib-and-apache 86 | 87 | WORKDIR /opt/shibboleth-sp 88 | 89 | COPY files/proxy.conf /etc/apache2/conf.d/ 90 | COPY files/shib.conf /etc/apache2/conf.d/ 91 | COPY files/*.xml /opt/shibboleth-sp/etc/shibboleth/ 92 | COPY files/*.pem /opt/shibboleth-sp/etc/shibboleth/ 93 | 94 | RUN sed -i s/SSLMutex/#SSLMutex/g /etc/apache2/conf.d/ssl.conf && \ 95 | sed -i "s/#ServerName.*/ServerName localhost:80/g" /etc/apache2/httpd.conf && \ 96 | sed -i "s/UseCanonicalName Off/UseCanonicalName On/g" /etc/apache2/httpd.conf 97 | 98 | CMD ["/opt/shibboleth-sp/sbin/start-shib-and-apache"] 99 | -------------------------------------------------------------------------------- /docker/shiny-apache-shib-sp/files/attribute-map.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docker/shiny-apache-shib-sp/files/proxy.conf: -------------------------------------------------------------------------------- 1 | LoadModule proxy_module modules/mod_proxy.so 2 | LoadModule proxy_ajp_module modules/mod_proxy_ajp.so 3 | LoadModule proxy_http_module modules/mod_proxy_http.so 4 | LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so 5 | 6 | ProxyPass /idp ajp://shiny-idp:8009/idp 7 | ProxyPassReverse /idp ajp://shiny-idp:8009/idp 8 | 9 | ProxyPassMatch /shiny/(.+)/websocket/ ws://shiny:3838/$1/websocket 10 | ProxyPassMatch /shiny/(.+) http://shiny:3838/$1 11 | -------------------------------------------------------------------------------- /docker/shiny-apache-shib-sp/files/saml-metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | localdomain 26 | 27 | 28 | 29 | 30 | 31 | MIIDkjCCAnoCCQCYAsXeiFCDcDANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMC 32 | VVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdPbHltcGlhMRswGQYDVQQKDBJDYXNj 33 | YWRpYSBBbmFseXRpY3MxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2NhbGRvbWFpbjEf 34 | MB0GCSqGSIb3DQEJARYQZG9ja2VyQGxvY2FsaG9zdDAeFw0xODA1MTgxNzA4Mjda 35 | Fw0zODA1MTMxNzA4MjdaMIGKMQswCQYDVQQGEwJVUzELMAkGA1UECAwCV0ExEDAO 36 | BgNVBAcMB09seW1waWExGzAZBgNVBAoMEkNhc2NhZGlhIEFuYWx5dGljczEeMBwG 37 | A1UEAwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMR8wHQYJKoZIhvcNAQkBFhBkb2Nr 38 | ZXJAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoiIh 39 | ucGDxgBPI7bjn9ze/jh0eT8An4BmHObw/xjq5REcx0/hq8A9oDmUQacsjP0+KWAC 40 | rxc9JHdcL+TgZJGcrhkUdAhGkeEvgywP+UJh/BTAfBMMvHkWGxM0cZjpjfdzxEbn 41 | v/qanw8KKjlaOo7rf3ia8nUDfKgYGx+PlPylUvlvI1C0hkHbmlaxsdvCLIRQRYhZ 42 | cWyRb2b9+UXJ2zuGZJUXXjvbXGZ8Loftlzjv64WiM5RPytzL1pVoc0OWpWvt1hLI 43 | 5VeG7GiPYhjf1kVxFSjv0S1w6lldBAkCoPQcSTrfHnVO3MvN0MdR69UWfgHmq1A7 44 | 5ovxIQaGd3p5jBtXNwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBZgIlOr/utsLJ0 45 | WT6uVBTXyWlUYi3yhKkLk7B0QRuVycYG5KNYs9hiVkFDpCkiOeR7hhgUIZVSe8VN 46 | HF9l3zJdLQ0gXAe6fgkNhxdo9fB9/jYo5gu6H+p6b0T/9OrrrUKEHvBhYR7inus7 47 | /eLN3s9aWhzp8uAaBZ0UVCat944inzWMnT1nQhw3LVwfizJGcTKAdB8T50OKQhvo 48 | Y/Xtc7RBa8bSu/q9nZ2xvdDgvJsssaqkeaRDgo7tpgs71DU4LyS1ph9O+lhsAgt8 49 | KwTji7X9VFAIUuWbuQfJl2ZQ6uyW6pOcTquPiAR7OX2Fc+ZrfAYDdDiCwpf80Inp 50 | OfwsJYfW 51 | 52 | 53 | 54 | 55 | 56 | urn:oasis:names:tc:SAML:2.0:nameid-format:persistent 57 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 58 | 59 | 61 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | MIIDkjCCAnoCCQDYf7lTcIsNOjANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMC 90 | VVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdPbHltcGlhMRswGQYDVQQKDBJDYXNj 91 | YWRpYSBBbmFseXRpY3MxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2NhbGRvbWFpbjEf 92 | MB0GCSqGSIb3DQEJARYQZG9ja2VyQGxvY2FsaG9zdDAeFw0xODA1MTgxNzA4MjZa 93 | Fw0zODA1MTMxNzA4MjZaMIGKMQswCQYDVQQGEwJVUzELMAkGA1UECAwCV0ExEDAO 94 | BgNVBAcMB09seW1waWExGzAZBgNVBAoMEkNhc2NhZGlhIEFuYWx5dGljczEeMBwG 95 | A1UEAwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMR8wHQYJKoZIhvcNAQkBFhBkb2Nr 96 | ZXJAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArtRF 97 | xJlPBEkhHl0DK0wutb4/5mixaL0bcydYwvvJxYdzpBcpJusJTpUg+ljQbwAT9Ln3 98 | Usg3fipsskkVQRoPPihbmgszRpi5qO4BoQhB1zoLshsT3hiuZGSeiVhUTOPtiMI3 99 | flOcicsSXKlXzdnILYGiFa26UltSef/KIF/5yHCVPCLgKDwmXmXx1ps990o/3qqC 100 | 17MCC+VxmMBuiyn+G22DFD5lHFxnppoc+EiWx53JdcvQwF2gfClGFEQjDEYuIRgr 101 | iwaWpHqIm7iGcyk6YZdRHR6AXSewOeTcZjPjVtpY0F6uHiGUXT7+Nj05QZG4f+7F 102 | zXcybcgmj/qg4ZsXZQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAdYMVfT6V9etxD 103 | ogZ1oUmUat/3HeN14LWPllRVc50CJ88gX4beiTkoiy+1t+3wRL0kb+w0NScGHiDt 104 | jqPJ+7WtlsBdEBgVsd1SrmUr7yG8iAYctbYnXZbrj5YPEx18ikfKy84chXxbotpn 105 | cqhx15PehLgfnktYRmsQnBXkvM8ziCnhjmbITdqVrarbYOqH0wKfj0YIehg1vum3 106 | xtryZVQ7cT28hFR9iraTTDnHqqTCFsQJhzomoVjLXyXY1q9EiGj5CWz+WzOKZxPg 107 | dj6O1AwhTPXcmPHYGO96SZpZaQaUWJwkp2L5qGYk3kaelHQJfsqQ8u/N31OtcUXs 108 | 2LqrhpOb 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | urn:oasis:names:tc:SAML:2.0:nameid-format:persistent 119 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 120 | 121 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /docker/shiny-apache-shib-sp/files/shib.conf: -------------------------------------------------------------------------------- 1 | LoadModule mod_shib /opt/shibboleth-sp/lib/shibboleth/mod_shib_24.so 2 | ShibCompatValidUser Off 3 | 4 | 5 | AuthType None 6 | Require all granted 7 | 8 | 9 | 10 | 11 | AuthType None 12 | Require all granted 13 | 14 | Alias /shibboleth-sp/main.css /opt/shibboleth-sp/share/shibboleth/main.css 15 | 16 | 17 | # Add a section below for any url path that should be gated by shib 18 | 19 | 20 | AuthType shibboleth 21 | ShibRequestSetting requireSession 1 22 | ShibUseHeaders On 23 | require shib-session 24 | 25 | -------------------------------------------------------------------------------- /docker/shiny-apache-shib-sp/files/shibboleth2.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | SAML2 SAML1 23 | 24 | 25 | SAML2 Local 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docker/shiny-apache-shib-sp/files/sp-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDkjCCAnoCCQDYf7lTcIsNOjANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMC 3 | VVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdPbHltcGlhMRswGQYDVQQKDBJDYXNj 4 | YWRpYSBBbmFseXRpY3MxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2NhbGRvbWFpbjEf 5 | MB0GCSqGSIb3DQEJARYQZG9ja2VyQGxvY2FsaG9zdDAeFw0xODA1MTgxNzA4MjZa 6 | Fw0zODA1MTMxNzA4MjZaMIGKMQswCQYDVQQGEwJVUzELMAkGA1UECAwCV0ExEDAO 7 | BgNVBAcMB09seW1waWExGzAZBgNVBAoMEkNhc2NhZGlhIEFuYWx5dGljczEeMBwG 8 | A1UEAwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMR8wHQYJKoZIhvcNAQkBFhBkb2Nr 9 | ZXJAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArtRF 10 | xJlPBEkhHl0DK0wutb4/5mixaL0bcydYwvvJxYdzpBcpJusJTpUg+ljQbwAT9Ln3 11 | Usg3fipsskkVQRoPPihbmgszRpi5qO4BoQhB1zoLshsT3hiuZGSeiVhUTOPtiMI3 12 | flOcicsSXKlXzdnILYGiFa26UltSef/KIF/5yHCVPCLgKDwmXmXx1ps990o/3qqC 13 | 17MCC+VxmMBuiyn+G22DFD5lHFxnppoc+EiWx53JdcvQwF2gfClGFEQjDEYuIRgr 14 | iwaWpHqIm7iGcyk6YZdRHR6AXSewOeTcZjPjVtpY0F6uHiGUXT7+Nj05QZG4f+7F 15 | zXcybcgmj/qg4ZsXZQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAdYMVfT6V9etxD 16 | ogZ1oUmUat/3HeN14LWPllRVc50CJ88gX4beiTkoiy+1t+3wRL0kb+w0NScGHiDt 17 | jqPJ+7WtlsBdEBgVsd1SrmUr7yG8iAYctbYnXZbrj5YPEx18ikfKy84chXxbotpn 18 | cqhx15PehLgfnktYRmsQnBXkvM8ziCnhjmbITdqVrarbYOqH0wKfj0YIehg1vum3 19 | xtryZVQ7cT28hFR9iraTTDnHqqTCFsQJhzomoVjLXyXY1q9EiGj5CWz+WzOKZxPg 20 | dj6O1AwhTPXcmPHYGO96SZpZaQaUWJwkp2L5qGYk3kaelHQJfsqQ8u/N31OtcUXs 21 | 2LqrhpOb 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /docker/shiny-apache-shib-sp/files/sp-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCu1EXEmU8ESSEe 3 | XQMrTC61vj/maLFovRtzJ1jC+8nFh3OkFykm6wlOlSD6WNBvABP0ufdSyDd+Kmyy 4 | SRVBGg8+KFuaCzNGmLmo7gGhCEHXOguyGxPeGK5kZJ6JWFRM4+2Iwjd+U5yJyxJc 5 | qVfN2cgtgaIVrbpSW1J5/8ogX/nIcJU8IuAoPCZeZfHWmz33Sj/eqoLXswIL5XGY 6 | wG6LKf4bbYMUPmUcXGemmhz4SJbHncl1y9DAXaB8KUYURCMMRi4hGCuLBpakeoib 7 | uIZzKTphl1EdHoBdJ7A55NxmM+NW2ljQXq4eIZRdPv42PTlBkbh/7sXNdzJtyCaP 8 | +qDhmxdlAgMBAAECggEBAKzDAzalsNmxUlLo4wrUO4xJNmf/qOCxjwCaLzJvEhJq 9 | KbJLWNUmiYnoADCjt0UZNJ8vbeGWDJBWaBc99QziLZHk27A7xS3MGht/Joj02etP 10 | ZuNXsqhUh3CZpbhfWt6olcAA/EmPYi8gR0Ld7PB0d0XQxlTZ2jcsGzKHvDuF3BVe 11 | 2Nrw285WkGW7PWvIiU4ncWsqpKSOiqryuSQqiLVHsinm4vO2/7v8HYmTcczcwMvw 12 | G8Hp8qAUrwQcS2/qcGEIvBYmR1I6h2c25vn4go3nkRxb1qqkYyKrIS4xZfY/g0aF 13 | Pg7V34nrdhIPZKFKDCuehT4FGGsU9cJ5DxQqgJ7rz7kCgYEA3jceMObXWzTE5ma5 14 | 493IWNL/zDTXN4SF7tvjjaSgku9vJq5JgiWPO/4PyK89P1Rx/FTTpoSwZZ6ZRj5H 15 | BbX8pquC08fIf8Mr9c4G0vAFdyo/y5He+C6XCK+HF0GGYoSuETSWDSnSYWLqW2fp 16 | OOZhYYKV7N0eRNkjBfoQVl4TS0sCgYEAyWjUv5OKy1HO4uI/LK18j1HSw+vTN2D8 17 | DfLefORaaZuq81vGJjUfv87E7hW9rPkNrl3wzW8TUnAJi8bhj7yyClJadkT4dr1j 18 | rGg7c3cVMCK6PwGAAVXPCk+rurFvmiSzRzBwJQ3pm9XW18nVvSZT02sCEBz8g1P2 19 | v9Aao+hiSg8CgYEAsindAfZDGnRPni8kwYazOExMHS0MlQ2i2KTiaFFjEQv5wTih 20 | 5UA5/C6x9wRRhfItxdM5MtxWFdO4LnKGPRTxcaw3o5cdsRoJp/W80OjyaN2t8oiN 21 | Dc1E+QjKtiGqHlkkutS/reQnMj+9iPXiLuW/lA/AJv4OY8L4arVY3fZlX8sCgYAt 22 | v3gDg9nU0OIzOryqw0U1sJo1Ek3JmGfoKzBKIfw/XLJ50HCzoQFzKd4lTh7lOTTY 23 | VFIr93zmDri8XRJC+dNe8NHHZ2cgYWhQcuR+F6BibKDtSsPuibUbXHlfUIpO8uMd 24 | 2my+nehgEzRXk2rPKfOEZBv12P+qPNohO32xmUkqFQKBgEbcGluYY/roZmj/UsEL 25 | oOjtg2yltYJQF00NgX/RmiSOJKpdjNTyRxDpP0h1G4W0SbeLjYfUZN/d3xfhvjx0 26 | wtonLoil16C60pFCqL7Lhiv68NpAoUocd+wsAqffzMFw9hR/Xys+c5yrz/KqlEFP 27 | 0td9ewGKqfSuiU5rhPK2Ip3e 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /docker/shiny-idp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM scottcame/shiny-tomcat8-proxied 2 | 3 | LABEL maintainer="Scott Came (scottcame10@gmail.com)" \ 4 | org.label-schema.description="Image with Shibboleth Identity Provider to support shiny demo" \ 5 | org.label-schema.vcs-url="https://github.com/scottcame/shiny-microservice-demo/docker/shiny-idp" 6 | 7 | WORKDIR /tmp 8 | 9 | # note that images (or other resources) used by the Velocity templates in the webapp have to be installed in the war file, though 10 | # the .vm resources themselves can be copied into /opt/shibboleth-idp/views/ 11 | # COPY files/*.png /tmp/ 12 | 13 | RUN curl -SsO http://shibboleth.net/downloads/identity-provider/3.3.2/shibboleth-identity-provider-3.3.2.zip && \ 14 | unzip shibboleth-identity-provider-3.3.2.zip && cd shibboleth-identity-provider-3.3.2 && \ 15 | echo "idp.entityID=https://idp.localhost.localdomain/idp/shibboleth" > props && \ 16 | bin/install.sh -Didp.target.dir=/opt/shibboleth-idp -Didp.host.name=localhost -Didp.sealer.password=password \ 17 | -Didp.keystore.password=password -Didp.src.dir=/tmp/shibboleth-identity-provider-3.3.2 -Didp.scope=localdomain \ 18 | -Didp.noprompt=true -Didp.merge.properties=props && \ 19 | cd /opt/shibboleth-idp/war && mkdir tmp && \ 20 | mv idp.war tmp/ && cd tmp && \ 21 | unzip idp.war && \ 22 | curl -SsO https://repo1.maven.org/maven2/jstl/jstl/1.2/jstl-1.2.jar && \ 23 | mv jstl-1.2.jar WEB-INF/lib && \ 24 | # mv /tmp/*.png images/ && \ 25 | cd .. && jar -cvfM idp.war -C tmp/ . && \ 26 | rm -rf tmp && rm -rf /tmp/* 27 | 28 | RUN cp -r /opt/shibboleth-idp/conf /tmp/ 29 | 30 | COPY files/saml-metadata.xml /opt/shibboleth-idp/metadata/saml-metadata.xml 31 | COPY files/access-control.xml /opt/shibboleth-idp/conf/access-control.xml 32 | COPY files/attribute-filter.xml /opt/shibboleth-idp/conf/attribute-filter.xml 33 | COPY files/attribute-resolver.xml /opt/shibboleth-idp/conf/attribute-resolver.xml 34 | COPY files/relying-party.xml /opt/shibboleth-idp/conf/relying-party.xml 35 | COPY files/metadata-providers.xml /opt/shibboleth-idp/conf/metadata-providers.xml 36 | COPY files/ldap.properties /opt/shibboleth-idp/conf/ldap.properties 37 | COPY files/idp.properties /opt/shibboleth-idp/conf/idp.properties 38 | COPY files/idp-signing-*.pem /opt/shibboleth-idp/credentials/ 39 | COPY files/login.vm /opt/shibboleth-idp/views/ 40 | 41 | RUN mkdir -p /opt/tomcat/conf/Catalina/localhost 42 | RUN echo '' > /opt/tomcat/conf/Catalina/localhost/idp.xml 43 | 44 | WORKDIR /opt/shibboleth-idp 45 | -------------------------------------------------------------------------------- /docker/shiny-idp/files/access-control.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /docker/shiny-idp/files/attribute-filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /docker/shiny-idp/files/attribute-resolver.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 43 | 44 | 45 | 46 | 47 | 54 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docker/shiny-idp/files/idp-signing-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDkjCCAnoCCQCYAsXeiFCDcDANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMC 3 | VVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdPbHltcGlhMRswGQYDVQQKDBJDYXNj 4 | YWRpYSBBbmFseXRpY3MxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2NhbGRvbWFpbjEf 5 | MB0GCSqGSIb3DQEJARYQZG9ja2VyQGxvY2FsaG9zdDAeFw0xODA1MTgxNzA4Mjda 6 | Fw0zODA1MTMxNzA4MjdaMIGKMQswCQYDVQQGEwJVUzELMAkGA1UECAwCV0ExEDAO 7 | BgNVBAcMB09seW1waWExGzAZBgNVBAoMEkNhc2NhZGlhIEFuYWx5dGljczEeMBwG 8 | A1UEAwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMR8wHQYJKoZIhvcNAQkBFhBkb2Nr 9 | ZXJAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoiIh 10 | ucGDxgBPI7bjn9ze/jh0eT8An4BmHObw/xjq5REcx0/hq8A9oDmUQacsjP0+KWAC 11 | rxc9JHdcL+TgZJGcrhkUdAhGkeEvgywP+UJh/BTAfBMMvHkWGxM0cZjpjfdzxEbn 12 | v/qanw8KKjlaOo7rf3ia8nUDfKgYGx+PlPylUvlvI1C0hkHbmlaxsdvCLIRQRYhZ 13 | cWyRb2b9+UXJ2zuGZJUXXjvbXGZ8Loftlzjv64WiM5RPytzL1pVoc0OWpWvt1hLI 14 | 5VeG7GiPYhjf1kVxFSjv0S1w6lldBAkCoPQcSTrfHnVO3MvN0MdR69UWfgHmq1A7 15 | 5ovxIQaGd3p5jBtXNwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBZgIlOr/utsLJ0 16 | WT6uVBTXyWlUYi3yhKkLk7B0QRuVycYG5KNYs9hiVkFDpCkiOeR7hhgUIZVSe8VN 17 | HF9l3zJdLQ0gXAe6fgkNhxdo9fB9/jYo5gu6H+p6b0T/9OrrrUKEHvBhYR7inus7 18 | /eLN3s9aWhzp8uAaBZ0UVCat944inzWMnT1nQhw3LVwfizJGcTKAdB8T50OKQhvo 19 | Y/Xtc7RBa8bSu/q9nZ2xvdDgvJsssaqkeaRDgo7tpgs71DU4LyS1ph9O+lhsAgt8 20 | KwTji7X9VFAIUuWbuQfJl2ZQ6uyW6pOcTquPiAR7OX2Fc+ZrfAYDdDiCwpf80Inp 21 | OfwsJYfW 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /docker/shiny-idp/files/idp-signing-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCiIiG5wYPGAE8j 3 | tuOf3N7+OHR5PwCfgGYc5vD/GOrlERzHT+GrwD2gOZRBpyyM/T4pYAKvFz0kd1wv 4 | 5OBkkZyuGRR0CEaR4S+DLA/5QmH8FMB8Ewy8eRYbEzRxmOmN93PERue/+pqfDwoq 5 | OVo6jut/eJrydQN8qBgbH4+U/KVS+W8jULSGQduaVrGx28IshFBFiFlxbJFvZv35 6 | RcnbO4ZklRdeO9tcZnwuh+2XOO/rhaIzlE/K3MvWlWhzQ5ala+3WEsjlV4bsaI9i 7 | GN/WRXEVKO/RLXDqWV0ECQKg9BxJOt8edU7cy83Qx1Hr1RZ+AearUDvmi/EhBoZ3 8 | enmMG1c3AgMBAAECggEAU+fOBE+9Xi6yxgzT59tqG64juMt+Cw1ryvFJLvs6NKmS 9 | dyND6ppmShECRKe7SouUK91gBjTEk6ahsreD2QfySbb4+sN9oekjqYKYEarlAovK 10 | wWsqYC9Z3VEnBtLXq3ywEJeRP6z1b/Nck1Vy+HMWNLW5mlgsIcrsDr1alQPamwFg 11 | JZOUKcVSPzamjgll5kc+4CltZY26yyjToJnYlNny51iGB1tKl+4y7wBR8t1yfGWE 12 | StDl2Zx4Xj0z5fnGq7udLbFVL9JNkvkQOg5IZ8gwQNhHtjy9DmYInClt+YpyHIZC 13 | PQpEa1JF5rZnpgd9CQ5KIR5qdB/+BkpxRtc9wNYXgQKBgQDSQpPSzMSyyTSQHNJy 14 | v0TQUfMfsfiK66hNwTDvuU/CrpWDo4TPz4BAUw0mQgLy94wwXxM/Rvf1tpsDa4fh 15 | P/Ft5Cyg0CDMgVcY/0Td4zG/LJ9mnaHclVO8YamuCFzJrluIeQjahtHBYP3eZRWt 16 | nvR4cvPuSSBCXpM2DAacBrd0ZwKBgQDFZ135cgr45dajIcNDxmWncon7eA4fv6Yu 17 | cSnykV8hgimf3hch3kqpannGbui3SR3SM4KZawc1387H6n6YOCSJHQ4URJ6UNyXZ 18 | Jsl7bXEMkV5EKbL8UhmnBLkqmz6uTnu2ofKeI94U0pqTOZU1PQvGsBlPUROBTZKg 19 | cx4VrZPEsQKBgCVlQfVUBgfmUTrwZV2TNyH18U/Jz3KlxyFNIu7//neZpW3sP0rW 20 | lPDb1JLhWrTr4jsYLcwrSx6gg6FwFpKxVLc+xdE0MyEsP9lqTU1JgyeFQDR4BLm+ 21 | tU3j8NHLGvWj1RPIsxJquBO0tHJBeEGQ69ogV9Ihn2MufvA141cMusQxAoGBAJ9B 22 | bUc5AjEa+7ZQHsAm5wvYFAmUKZDjhKYjFbxkG2NlJz+aZP8l3wYeqG+2Onjju/NB 23 | KzOqbP7BuIkAXXFgmdkkX59qXKUmeJpf+FxjRrjk7i//lC6L7bYY0WnWJRNqrdQB 24 | g0KhnSEfZyUvZ3iz7zQ0Dbc3qYy/kHNxa+wBRR2BAoGBAIAA5GkmBqIN4BK8BUd1 25 | HWbRw8UJw7pEolfwlx1U0RAztJ8I2CC0lchAPk3X92FeDldFu6JgfWPEmetQPKbr 26 | o2vEvFtc7IVDEBMF/PPKPQYswRVMVYoQCMXHyRkQ3qcZpcZFOo2vKxPrL8n/9uZ6 27 | eMFodVOOi0+DyP6zbkp5izs/ 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /docker/shiny-idp/files/idp.properties: -------------------------------------------------------------------------------- 1 | # Load any additional property resources from a comma-delimited list 2 | idp.additionalProperties= /conf/ldap.properties, /conf/saml-nameid.properties, /conf/services.properties 3 | 4 | # Set the entityID of the IdP 5 | idp.entityID= https://idp.localhost.localdomain/idp/shibboleth 6 | 7 | # Set the scope used in the attribute resolver for scoped attributes 8 | idp.scope= localdomain 9 | 10 | # General cookie properties (maxAge only applies to persistent cookies) 11 | #idp.cookie.secure = false 12 | #idp.cookie.httpOnly = true 13 | #idp.cookie.domain = 14 | #idp.cookie.path = 15 | #idp.cookie.maxAge = 31536000 16 | 17 | # Set the location of user-supplied web flow definitions 18 | #idp.webflows = %{idp.home}/flows 19 | 20 | # Set the location of Velocity view templates 21 | #idp.views = %{idp.home}/views 22 | 23 | # Settings for internal AES encryption key 24 | #idp.sealer.storeType = JCEKS 25 | #idp.sealer.updateInterval = PT15M 26 | #idp.sealer.aliasBase = secret 27 | idp.sealer.storeResource= %{idp.home}/credentials/sealer.jks 28 | idp.sealer.versionResource= %{idp.home}/credentials/sealer.kver 29 | idp.sealer.storePassword= password 30 | idp.sealer.keyPassword= password 31 | 32 | # Settings for public/private signing and encryption key(s) 33 | # During decryption key rollover, point the ".2" properties at a second 34 | # keypair, uncomment in credentials.xml, then publish it in your metadata. 35 | idp.signing.key= %{idp.home}/credentials/idp-signing-key.pem 36 | idp.signing.cert= %{idp.home}/credentials/idp-signing-cert.pem 37 | idp.encryption.key= %{idp.home}/credentials/idp-encryption.key 38 | idp.encryption.cert= %{idp.home}/credentials/idp-encryption.crt 39 | #idp.encryption.key.2 = %{idp.home}/credentials/idp-encryption-old.key 40 | #idp.encryption.cert.2 = %{idp.home}/credentials/idp-encryption-old.crt 41 | 42 | # Sets the bean ID to use as a default security configuration set 43 | #idp.security.config = shibboleth.DefaultSecurityConfiguration 44 | 45 | # To default to SHA-1, set to shibboleth.SigningConfiguration.SHA1 46 | #idp.signing.config = shibboleth.SigningConfiguration.SHA256 47 | 48 | # Configures trust evaluation of keys used by services at runtime 49 | # Defaults to supporting both explicit key and PKIX using SAML metadata. 50 | #idp.trust.signatures = shibboleth.ChainingSignatureTrustEngine 51 | # To pick only one set to one of: 52 | # shibboleth.ExplicitKeySignatureTrustEngine, shibboleth.PKIXSignatureTrustEngine 53 | #idp.trust.certificates = shibboleth.ChainingX509TrustEngine 54 | # To pick only one set to one of: 55 | # shibboleth.ExplicitKeyX509TrustEngine, shibboleth.PKIXX509TrustEngine 56 | 57 | # If true, encryption will happen whenever a key to use can be located, but 58 | # failure to encrypt won't result in request failure. 59 | #idp.encryption.optional = false 60 | 61 | # Configuration of client- and server-side storage plugins 62 | #idp.storage.cleanupInterval = PT10M 63 | #idp.storage.htmlLocalStorage = false 64 | 65 | # Set to true to expose more detailed errors in responses to SPs 66 | #idp.errors.detailed = false 67 | # Set to false to skip signing of SAML response messages that signal errors 68 | #idp.errors.signed = true 69 | # Name of bean containing a list of Java exception classes to ignore 70 | #idp.errors.excludedExceptions = ExceptionClassListBean 71 | # Name of bean containing a property set mapping exception names to views 72 | #idp.errors.exceptionMappings = ExceptionToViewPropertyBean 73 | # Set if a different default view name for events and exceptions is needed 74 | #idp.errors.defaultView = error 75 | 76 | # Set to false to disable the IdP session layer 77 | #idp.session.enabled = true 78 | 79 | # Set to "shibboleth.StorageService" for server-side storage of user sessions 80 | #idp.session.StorageService = shibboleth.ClientSessionStorageService 81 | 82 | # Size of session IDs 83 | #idp.session.idSize = 32 84 | # Bind sessions to IP addresses 85 | #idp.session.consistentAddress = true 86 | # Inactivity timeout 87 | #idp.session.timeout = PT60M 88 | # Extra time to store sessions for logout 89 | #idp.session.slop = PT0S 90 | # Tolerate storage-related errors 91 | #idp.session.maskStorageFailure = false 92 | # Track information about SPs logged into 93 | #idp.session.trackSPSessions = false 94 | # Support lookup by SP for SAML logout 95 | #idp.session.secondaryServiceIndex = false 96 | # Length of time to track SP sessions 97 | #idp.session.defaultSPlifetime = PT2H 98 | 99 | # Regular expression matching login flows to enable, e.g. IPAddress|Password 100 | idp.authn.flows= Password 101 | 102 | # Regular expression of forced "initial" methods when no session exists, 103 | # usually in conjunction with the idp.authn.resolveAttribute property below. 104 | #idp.authn.flows.initial = Password 105 | 106 | # Set to an attribute ID to resolve prior to selecting authentication flows; 107 | # its values are used to filter the flows to allow. 108 | #idp.authn.resolveAttribute = eduPersonAssurance 109 | 110 | # Default lifetime and timeout of various authentication methods 111 | #idp.authn.defaultLifetime = PT60M 112 | #idp.authn.defaultTimeout = PT30M 113 | 114 | # Whether to prioritize "active" results when an SP requests more than 115 | # one possible matching login method (V2 behavior was to favor them) 116 | #idp.authn.favorSSO = true 117 | 118 | # Whether to fail requests when a user identity after authentication 119 | # doesn't match the identity in a pre-existing session. 120 | #idp.authn.identitySwitchIsError = false 121 | 122 | # Set to "shibboleth.StorageService" or custom bean for alternate storage of consent 123 | #idp.consent.StorageService = shibboleth.ClientPersistentStorageService 124 | 125 | # Set to "shibboleth.consent.AttributeConsentStorageKey" to use an attribute 126 | # to key user consent storage records (and set the attribute name) 127 | #idp.consent.userStorageKey = shibboleth.consent.PrincipalConsentStorageKey 128 | #idp.consent.userStorageKeyAttribute = uid 129 | 130 | # Flags controlling how built-in attribute consent feature operates 131 | #idp.consent.allowDoNotRemember = true 132 | #idp.consent.allowGlobal = true 133 | #idp.consent.allowPerAttribute = false 134 | 135 | # Whether attribute values and terms of use text are compared 136 | #idp.consent.compareValues = false 137 | # Maximum number of consent records for space-limited storage (e.g. cookies) 138 | #idp.consent.maxStoredRecords = 10 139 | # Maximum number of consent records for larger/server-side storage (0 = no limit) 140 | #idp.consent.expandedMaxStoredRecords = 0 141 | 142 | # Time in milliseconds to expire consent storage records. 143 | #idp.consent.storageRecordLifetime = P1Y 144 | 145 | # Whether to lookup metadata, etc. for every SP involved in a logout 146 | # for use by user interface logic; adds overhead so off by default. 147 | #idp.logout.elaboration = false 148 | 149 | # Whether to require logout requests be signed/authenticated. 150 | #idp.logout.authenticated = true 151 | 152 | # Message freshness and replay cache tuning 153 | #idp.policy.messageLifetime = PT3M 154 | #idp.policy.clockSkew = PT3M 155 | 156 | # Set to custom bean for alternate storage of replay cache 157 | #idp.replayCache.StorageService = shibboleth.StorageService 158 | 159 | # Toggles whether to allow outbound messages via SAML artifact 160 | #idp.artifact.enabled = true 161 | # Suppresses typical signing/encryption when artifact binding used 162 | #idp.artifact.secureChannel = true 163 | # May differ to direct SAML 2 artifact lookups to specific server nodes 164 | #idp.artifact.endpointIndex = 2 165 | # Set to custom bean for alternate storage of artifact map state 166 | #idp.artifact.StorageService = shibboleth.StorageService 167 | 168 | # Name of access control policy for various admin flows 169 | idp.status.accessPolicy= AccessByIPAddress 170 | idp.resolvertest.accessPolicy= AccessByIPAddress 171 | idp.reload.accessPolicy= AccessByIPAddress 172 | 173 | # Comma-delimited languages to use if not match can be found with the 174 | # browser-supported languages, defaults to an empty list. 175 | idp.ui.fallbackLanguages= en,fr,de 176 | 177 | # Storage service used by CAS protocol 178 | # Defaults to shibboleth.StorageService (in-memory) 179 | # MUST be server-side storage (e.g. in-memory, memcached, database) 180 | # NOTE that idp.session.StorageService requires server-side storage 181 | # when CAS protocol is enabled 182 | #idp.cas.StorageService=shibboleth.StorageService 183 | 184 | # CAS service registry implementation class 185 | #idp.cas.serviceRegistryClass=net.shibboleth.idp.cas.service.PatternServiceRegistry 186 | 187 | # Profile flows in which the ProfileRequestContext should be exposed 188 | # in servlet request under the key "opensamlProfileRequestContext" 189 | #idp.profile.exposeProfileRequestContextInServletRequest = SAML2/POST/SSO,SAML2/Redirect/SSO 190 | 191 | # F-TICKS auditing - set salt to include hashed username 192 | #idp.fticks.federation=MyFederation 193 | #idp.fticks.algorithm=SHA-256 194 | #idp.fticks.salt=somethingsecret 195 | -------------------------------------------------------------------------------- /docker/shiny-idp/files/ldap.properties: -------------------------------------------------------------------------------- 1 | # LDAP authentication configuration, see authn/ldap-authn-config.xml 2 | # Note, this doesn't apply to the use of JAAS 3 | 4 | ## Authenticator strategy, either anonSearchAuthenticator, bindSearchAuthenticator, directAuthenticator, adAuthenticator 5 | #idp.authn.LDAP.authenticator = anonSearchAuthenticator 6 | 7 | ## Connection properties ## 8 | idp.authn.LDAP.ldapURL = ldap://shiny-openldap:389 9 | idp.authn.LDAP.useStartTLS = false 10 | #idp.authn.LDAP.useSSL = false 11 | #idp.authn.LDAP.connectTimeout = 3000 12 | 13 | ## SSL configuration, either jvmTrust, certificateTrust, or keyStoreTrust 14 | #idp.authn.LDAP.sslConfig = certificateTrust 15 | ## If using certificateTrust above, set to the trusted certificate's path 16 | #idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldap-server.crt 17 | ## If using keyStoreTrust above, set to the truststore path 18 | #idp.authn.LDAP.trustStore = %{idp.home}/credentials/ldap-server.truststore 19 | 20 | ## Return attributes during authentication 21 | ## NOTE: there is a separate property used for attribute resolution 22 | idp.authn.LDAP.returnAttributes = passwordExpirationTime,loginGraceRemaining 23 | 24 | ## DN resolution properties ## 25 | 26 | # Search DN resolution, used by anonSearchAuthenticator, bindSearchAuthenticator 27 | # for AD: CN=Users,DC=example,DC=org 28 | idp.authn.LDAP.baseDN = ou=users,dc=ldap,dc=localhost,dc=localdomain 29 | #idp.authn.LDAP.subtreeSearch = false 30 | idp.authn.LDAP.userFilter = (uid={user}) 31 | # bind search configuration 32 | # for AD: idp.authn.LDAP.bindDN=adminuser@domain.com 33 | idp.authn.LDAP.bindDN = ou=ldapadmin,ou=admins,dc=ldap,dc=localhost,dc=localdomain 34 | idp.authn.LDAP.bindDNCredential = password 35 | 36 | # Format DN resolution, used by directAuthenticator, adAuthenticator 37 | # for AD use idp.authn.LDAP.dnFormat=%s@domain.com 38 | idp.authn.LDAP.dnFormat = uid=%s,ou=users,dc=ldap,dc=localhost,dc=localdomain 39 | 40 | # LDAP attribute configuration, see attribute-resolver.xml 41 | # Note, this likely won't apply to the use of legacy V2 resolver configurations 42 | idp.attribute.resolver.LDAP.ldapURL = %{idp.authn.LDAP.ldapURL} 43 | idp.attribute.resolver.LDAP.baseDN = %{idp.authn.LDAP.baseDN:undefined} 44 | idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN:undefined} 45 | idp.attribute.resolver.LDAP.bindDNCredential = %{idp.authn.LDAP.bindDNCredential:undefined} 46 | idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true} 47 | idp.attribute.resolver.LDAP.trustCertificates = %{idp.authn.LDAP.trustCertificates:undefined} 48 | idp.attribute.resolver.LDAP.searchFilter = (uid=$resolutionContext.principal) 49 | idp.attribute.resolver.LDAP.returnAttributes = uid,sn,givenName,o,mail 50 | 51 | # LDAP pool configuration, used for both authn and DN resolution 52 | #idp.pool.LDAP.minSize = 3 53 | #idp.pool.LDAP.maxSize = 10 54 | #idp.pool.LDAP.validateOnCheckout = false 55 | #idp.pool.LDAP.validatePeriodically = true 56 | #idp.pool.LDAP.validatePeriod = 300 57 | #idp.pool.LDAP.prunePeriod = 300 58 | #idp.pool.LDAP.idleTime = 600 59 | #idp.pool.LDAP.blockWaitTime = 3000 60 | #idp.pool.LDAP.failFastInitialize = false 61 | -------------------------------------------------------------------------------- /docker/shiny-idp/files/login.vm: -------------------------------------------------------------------------------- 1 | 2 | #if ($authenticationErrorContext && $authenticationErrorContext.getClassifiedErrors().size() > 0 && $authenticationErrorContext.getClassifiedErrors().iterator().next() != "ReselectFlow") 3 | ## This handles errors that are classified by the message maps in the authentication config. 4 | #set ($eventId = $authenticationErrorContext.getClassifiedErrors().iterator().next()) 5 | #set ($eventKey = $springMacroRequestContext.getMessage("$eventId", "login")) 6 | #set ($message = $springMacroRequestContext.getMessage("${eventKey}.message", "Login Failure: $eventId")) 7 | #elseif ($authenticationErrorContext && $authenticationErrorContext.getExceptions().size() > 0) 8 | ## This handles login exceptions that are left unclassified. 9 | #set ($loginException = $authenticationErrorContext.getExceptions().get(0)) 10 | #if ($loginException.getMessage()) 11 | #set ($message = "Login Failure: $loginException.getMessage()") 12 | #else 13 | #set ($message = $loginException.toString()) 14 | #end 15 | #end 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 70 | 71 | 72 | 73 | 74 | 75 |
76 |
77 |
78 | Shiny Demo SAML Login 79 |
80 |
81 |
82 |
83 | 99 |
100 |
101 |
102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /docker/shiny-idp/files/metadata-providers.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docker/shiny-idp/files/relying-party.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /docker/shiny-idp/files/saml-metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | localdomain 26 | 27 | 28 | 29 | 30 | 31 | MIIDkjCCAnoCCQCYAsXeiFCDcDANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMC 32 | VVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdPbHltcGlhMRswGQYDVQQKDBJDYXNj 33 | YWRpYSBBbmFseXRpY3MxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2NhbGRvbWFpbjEf 34 | MB0GCSqGSIb3DQEJARYQZG9ja2VyQGxvY2FsaG9zdDAeFw0xODA1MTgxNzA4Mjda 35 | Fw0zODA1MTMxNzA4MjdaMIGKMQswCQYDVQQGEwJVUzELMAkGA1UECAwCV0ExEDAO 36 | BgNVBAcMB09seW1waWExGzAZBgNVBAoMEkNhc2NhZGlhIEFuYWx5dGljczEeMBwG 37 | A1UEAwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMR8wHQYJKoZIhvcNAQkBFhBkb2Nr 38 | ZXJAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoiIh 39 | ucGDxgBPI7bjn9ze/jh0eT8An4BmHObw/xjq5REcx0/hq8A9oDmUQacsjP0+KWAC 40 | rxc9JHdcL+TgZJGcrhkUdAhGkeEvgywP+UJh/BTAfBMMvHkWGxM0cZjpjfdzxEbn 41 | v/qanw8KKjlaOo7rf3ia8nUDfKgYGx+PlPylUvlvI1C0hkHbmlaxsdvCLIRQRYhZ 42 | cWyRb2b9+UXJ2zuGZJUXXjvbXGZ8Loftlzjv64WiM5RPytzL1pVoc0OWpWvt1hLI 43 | 5VeG7GiPYhjf1kVxFSjv0S1w6lldBAkCoPQcSTrfHnVO3MvN0MdR69UWfgHmq1A7 44 | 5ovxIQaGd3p5jBtXNwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBZgIlOr/utsLJ0 45 | WT6uVBTXyWlUYi3yhKkLk7B0QRuVycYG5KNYs9hiVkFDpCkiOeR7hhgUIZVSe8VN 46 | HF9l3zJdLQ0gXAe6fgkNhxdo9fB9/jYo5gu6H+p6b0T/9OrrrUKEHvBhYR7inus7 47 | /eLN3s9aWhzp8uAaBZ0UVCat944inzWMnT1nQhw3LVwfizJGcTKAdB8T50OKQhvo 48 | Y/Xtc7RBa8bSu/q9nZ2xvdDgvJsssaqkeaRDgo7tpgs71DU4LyS1ph9O+lhsAgt8 49 | KwTji7X9VFAIUuWbuQfJl2ZQ6uyW6pOcTquPiAR7OX2Fc+ZrfAYDdDiCwpf80Inp 50 | OfwsJYfW 51 | 52 | 53 | 54 | 55 | 56 | urn:oasis:names:tc:SAML:2.0:nameid-format:persistent 57 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 58 | 59 | 61 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | MIIDkjCCAnoCCQDYf7lTcIsNOjANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMC 90 | VVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdPbHltcGlhMRswGQYDVQQKDBJDYXNj 91 | YWRpYSBBbmFseXRpY3MxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2NhbGRvbWFpbjEf 92 | MB0GCSqGSIb3DQEJARYQZG9ja2VyQGxvY2FsaG9zdDAeFw0xODA1MTgxNzA4MjZa 93 | Fw0zODA1MTMxNzA4MjZaMIGKMQswCQYDVQQGEwJVUzELMAkGA1UECAwCV0ExEDAO 94 | BgNVBAcMB09seW1waWExGzAZBgNVBAoMEkNhc2NhZGlhIEFuYWx5dGljczEeMBwG 95 | A1UEAwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMR8wHQYJKoZIhvcNAQkBFhBkb2Nr 96 | ZXJAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArtRF 97 | xJlPBEkhHl0DK0wutb4/5mixaL0bcydYwvvJxYdzpBcpJusJTpUg+ljQbwAT9Ln3 98 | Usg3fipsskkVQRoPPihbmgszRpi5qO4BoQhB1zoLshsT3hiuZGSeiVhUTOPtiMI3 99 | flOcicsSXKlXzdnILYGiFa26UltSef/KIF/5yHCVPCLgKDwmXmXx1ps990o/3qqC 100 | 17MCC+VxmMBuiyn+G22DFD5lHFxnppoc+EiWx53JdcvQwF2gfClGFEQjDEYuIRgr 101 | iwaWpHqIm7iGcyk6YZdRHR6AXSewOeTcZjPjVtpY0F6uHiGUXT7+Nj05QZG4f+7F 102 | zXcybcgmj/qg4ZsXZQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAdYMVfT6V9etxD 103 | ogZ1oUmUat/3HeN14LWPllRVc50CJ88gX4beiTkoiy+1t+3wRL0kb+w0NScGHiDt 104 | jqPJ+7WtlsBdEBgVsd1SrmUr7yG8iAYctbYnXZbrj5YPEx18ikfKy84chXxbotpn 105 | cqhx15PehLgfnktYRmsQnBXkvM8ziCnhjmbITdqVrarbYOqH0wKfj0YIehg1vum3 106 | xtryZVQ7cT28hFR9iraTTDnHqqTCFsQJhzomoVjLXyXY1q9EiGj5CWz+WzOKZxPg 107 | dj6O1AwhTPXcmPHYGO96SZpZaQaUWJwkp2L5qGYk3kaelHQJfsqQ8u/N31OtcUXs 108 | 2LqrhpOb 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | urn:oasis:names:tc:SAML:2.0:nameid-format:persistent 119 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 120 | 121 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /docker/shiny-openldap/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM dinkel/openldap 2 | 3 | LABEL maintainer="Scott Came (scottcame10@gmail.com)" \ 4 | org.label-schema.description="Image with openldap server and some test users to support shiny demo" \ 5 | org.label-schema.vcs-url="https://github.com/scottcame/shiny-microservice-demo/docker/shiny-openldap" 6 | 7 | # docker run -d -p 1389:389 --name=shiny-openldap -e SLAPD_PASSWORD=password -e SLAPD_DOMAIN=ldap.localhost.localdomain shiny-openldap 8 | 9 | RUN mkdir -p /etc/ldap.dist/prepopulate 10 | 11 | COPY files/0*.ldif /etc/ldap.dist/prepopulate/ 12 | 13 | COPY files/9*.ldif /etc/ldap.dist/prepopulate/ 14 | -------------------------------------------------------------------------------- /docker/shiny-openldap/files/0110_ous.ldif: -------------------------------------------------------------------------------- 1 | dn: ou=users,dc=ldap,dc=localhost,dc=localdomain 2 | objectClass: organizationalUnit 3 | ou: users 4 | 5 | dn: ou=admins,dc=ldap,dc=localhost,dc=localdomain 6 | objectClass: organizationalUnit 7 | ou: admins 8 | -------------------------------------------------------------------------------- /docker/shiny-openldap/files/9001_testusers.ldif: -------------------------------------------------------------------------------- 1 | dn: cn=demouser1,ou=users,dc=ldap,dc=localhost,dc=localdomain 2 | objectClass: inetOrgPerson 3 | objectClass: organizationalPerson 4 | objectClass: simpleSecurityObject 5 | objectClass: person 6 | objectClass: top 7 | cn: testuser1 8 | ou: users 9 | sn: User 10 | givenName: Demo1 11 | o: Organization A 12 | mail: demouser1@localhost 13 | uid: demouser1 14 | userPassword:: e1NIQX1XNnBoNU1tNVB6OEdnaVVMYlBnekczN21qOWc9 15 | 16 | dn: cn=demouser2,ou=users,dc=ldap,dc=localhost,dc=localdomain 17 | objectClass: inetOrgPerson 18 | objectClass: organizationalPerson 19 | objectClass: simpleSecurityObject 20 | objectClass: person 21 | objectClass: top 22 | cn: testuser2 23 | ou: users 24 | sn: User 25 | givenName: Demo2 26 | o: Organization B 27 | mail: demouser2@localhost 28 | uid: demouser2 29 | userPassword:: e1NIQX1XNnBoNU1tNVB6OEdnaVVMYlBnekczN21qOWc9 30 | 31 | dn: cn=ldapadmin,ou=admins,dc=ldap,dc=localhost,dc=localdomain 32 | objectClass: inetOrgPerson 33 | objectClass: organizationalPerson 34 | objectClass: simpleSecurityObject 35 | objectClass: person 36 | objectClass: top 37 | cn: ldapadmin 38 | ou: admins 39 | sn: Administrator 40 | uid: ldapadmin 41 | userPassword:: e1NIQX1XNnBoNU1tNVB6OEdnaVVMYlBnekczN21qOWc9 42 | -------------------------------------------------------------------------------- /docker/shiny-tomcat8-proxied/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8u151-jdk-alpine3.7 2 | 3 | LABEL maintainer="Scott Came (scottcame10@gmail.com)" \ 4 | org.label-schema.description="Image with Apache Tomcat set up to be proxied by Apache mod proxy, to support shiny demo" \ 5 | org.label-schema.vcs-url="https://github.com/scottcame/shiny-microservice-demo/docker/shiny-tomcat8-proxied" 6 | 7 | RUN apk add --update bash curl unzip zip tar 8 | 9 | RUN sed -i -r -e 's/securerandom.source.+/securerandom.source=file:\/dev\/urandom/' /usr/lib/jvm/java-1.8-openjdk/jre/lib/security/java.security 10 | 11 | ENV CATALINA_HOME /opt/tomcat 12 | ENV PATH $CATALINA_HOME/bin:$PATH 13 | RUN mkdir -p "$CATALINA_HOME" 14 | WORKDIR $CATALINA_HOME 15 | 16 | RUN cd /tmp && \ 17 | curl -SsO https://archive.apache.org/dist/tomcat/tomcat-8/v8.0.50/bin/apache-tomcat-8.0.50.tar.gz && \ 18 | tar -xvf /tmp/apache-tomcat-8.0.50.tar.gz -C /opt/tomcat --strip-components=1 && \ 19 | rm $CATALINA_HOME/bin/*.bat && rm /tmp/apache-tomcat-8.0.50.tar.gz 20 | 21 | COPY files/server.xml conf/ 22 | COPY files/catalina.sh bin/ 23 | COPY files/catalina.properties /opt/tomcat/conf/ 24 | 25 | RUN chmod ugo+x $CATALINA_HOME/bin/catalina.sh 26 | RUN mkdir -p /opt/tomcat/shared/config 27 | 28 | CMD ["/opt/tomcat/bin/catalina.sh", "run"] 29 | -------------------------------------------------------------------------------- /docker/shiny-tomcat8-proxied/files/catalina.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # 17 | # List of comma-separated packages that start with or equal this string 18 | # will cause a security exception to be thrown when 19 | # passed to checkPackageAccess unless the 20 | # corresponding RuntimePermission ("accessClassInPackage."+package) has 21 | # been granted. 22 | package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.tomcat. 23 | # 24 | # List of comma-separated packages that start with or equal this string 25 | # will cause a security exception to be thrown when 26 | # passed to checkPackageDefinition unless the 27 | # corresponding RuntimePermission ("defineClassInPackage."+package) has 28 | # been granted. 29 | # 30 | # by default, no packages are restricted for definition, and none of 31 | # the class loaders supplied with the JDK call checkPackageDefinition. 32 | # 33 | package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,\ 34 | org.apache.jasper.,org.apache.naming.,org.apache.tomcat. 35 | 36 | # 37 | # 38 | # List of comma-separated paths defining the contents of the "common" 39 | # classloader. Prefixes should be used to define what is the repository type. 40 | # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. 41 | # If left as blank,the JVM system loader will be used as Catalina's "common" 42 | # loader. 43 | # Examples: 44 | # "foo": Add this folder as a class repository 45 | # "foo/*.jar": Add all the JARs of the specified folder as class 46 | # repositories 47 | # "foo/bar.jar": Add bar.jar as a class repository 48 | # 49 | # Note: Values are enclosed in double quotes ("...") in case either the 50 | # ${catalina.base} path or the ${catalina.home} path contains a comma. 51 | # Because double quotes are used for quoting, the double quote character 52 | # may not appear in a path. 53 | common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar" 54 | 55 | # 56 | # List of comma-separated paths defining the contents of the "server" 57 | # classloader. Prefixes should be used to define what is the repository type. 58 | # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. 59 | # If left as blank, the "common" loader will be used as Catalina's "server" 60 | # loader. 61 | # Examples: 62 | # "foo": Add this folder as a class repository 63 | # "foo/*.jar": Add all the JARs of the specified folder as class 64 | # repositories 65 | # "foo/bar.jar": Add bar.jar as a class repository 66 | # 67 | # Note: Values may be enclosed in double quotes ("...") in case either the 68 | # ${catalina.base} path or the ${catalina.home} path contains a comma. 69 | # Because double quotes are used for quoting, the double quote character 70 | # may not appear in a path. 71 | server.loader= 72 | 73 | # 74 | # List of comma-separated paths defining the contents of the "shared" 75 | # classloader. Prefixes should be used to define what is the repository type. 76 | # Path may be relative to the CATALINA_BASE path or absolute. If left as blank, 77 | # the "common" loader will be used as Catalina's "shared" loader. 78 | # Examples: 79 | # "foo": Add this folder as a class repository 80 | # "foo/*.jar": Add all the JARs of the specified folder as class 81 | # repositories 82 | # "foo/bar.jar": Add bar.jar as a class repository 83 | # Please note that for single jars, e.g. bar.jar, you need the URL form 84 | # starting with file:. 85 | # 86 | # Note: Values may be enclosed in double quotes ("...") in case either the 87 | # ${catalina.base} path or the ${catalina.home} path contains a comma. 88 | # Because double quotes are used for quoting, the double quote character 89 | # may not appear in a path. 90 | shared.loader=/opt/tomcat/shared,/opt/tomcat/shared/*.jar 91 | 92 | # Default list of JAR files that should not be scanned using the JarScanner 93 | # functionality. This is typically used to scan JARs for configuration 94 | # information. JARs that do not contain such information may be excluded from 95 | # the scan to speed up the scanning process. This is the default list. JARs on 96 | # this list are excluded from all scans. The list must be a comma separated list 97 | # of JAR file names. 98 | # The list of JARs to skip may be over-ridden at a Context level for individual 99 | # scan types by configuring a JarScanner with a nested JarScanFilter. 100 | # The JARs listed below include: 101 | # - Tomcat Bootstrap JARs 102 | # - Tomcat API JARs 103 | # - Catalina JARs 104 | # - Jasper JARs 105 | # - Tomcat JARs 106 | # - Common non-Tomcat JARs 107 | # - Test JARs (JUnit, Cobertura and dependencies) 108 | tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\ 109 | bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\ 110 | annotations-api.jar,el-api.jar,jsp-api.jar,servlet-api.jar,websocket-api.jar,\ 111 | catalina.jar,catalina-ant.jar,catalina-ha.jar,catalina-storeconfig.jar,\ 112 | catalina-tribes.jar,\ 113 | jasper.jar,jasper-el.jar,ecj-*.jar,\ 114 | tomcat-api.jar,tomcat-util.jar,tomcat-util-scan.jar,tomcat-coyote.jar,\ 115 | tomcat-dbcp.jar,tomcat-jni.jar,tomcat-websocket.jar,\ 116 | tomcat-i18n-en.jar,tomcat-i18n-es.jar,tomcat-i18n-fr.jar,tomcat-i18n-ja.jar,\ 117 | tomcat-juli-adapters.jar,catalina-jmx-remote.jar,catalina-ws.jar,\ 118 | tomcat-jdbc.jar,\ 119 | tools.jar,\ 120 | commons-beanutils*.jar,commons-codec*.jar,commons-collections*.jar,\ 121 | commons-dbcp*.jar,commons-digester*.jar,commons-fileupload*.jar,\ 122 | commons-httpclient*.jar,commons-io*.jar,commons-lang*.jar,commons-logging*.jar,\ 123 | commons-math*.jar,commons-pool*.jar,\ 124 | jstl.jar,taglibs-standard-spec-*.jar,\ 125 | geronimo-spec-jaxrpc*.jar,wsdl4j*.jar,\ 126 | ant.jar,ant-junit*.jar,aspectj*.jar,jmx.jar,h2*.jar,hibernate*.jar,httpclient*.jar,\ 127 | jmx-tools.jar,jta*.jar,log4j*.jar,mail*.jar,slf4j*.jar,\ 128 | xercesImpl.jar,xmlParserAPIs.jar,xml-apis.jar,\ 129 | junit.jar,junit-*.jar,ant-launcher.jar,\ 130 | cobertura-*.jar,asm-*.jar,dom4j-*.jar,icu4j-*.jar,jaxen-*.jar,jdom-*.jar,\ 131 | jetty-*.jar,oro-*.jar,servlet-api-*.jar,tagsoup-*.jar,xmlParserAPIs-*.jar 132 | 133 | # Default list of JAR files that should be scanned that overrides the default 134 | # jarsToSkip list above. This is typically used to include a specific JAR that 135 | # has been excluded by a broad file name pattern in the jarsToSkip list. 136 | # The list of JARs to scan may be over-ridden at a Context level for individual 137 | # scan types by configuring a JarScanner with a nested JarScanFilter. 138 | tomcat.util.scan.StandardJarScanFilter.jarsToScan=log4j-core*.jar,log4j-taglib*.jar,log4javascript*.jar 139 | 140 | # String cache configuration. 141 | tomcat.util.buf.StringCache.byte.enabled=true 142 | #tomcat.util.buf.StringCache.char.enabled=true 143 | #tomcat.util.buf.StringCache.trainThreshold=500000 144 | #tomcat.util.buf.StringCache.cacheSize=5000 145 | -------------------------------------------------------------------------------- /docker/shiny-tomcat8-proxied/files/catalina.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | # ----------------------------------------------------------------------------- 19 | # Control Script for the CATALINA Server 20 | # 21 | # Environment Variable Prerequisites 22 | # 23 | # Do not set the variables in this script. Instead put them into a script 24 | # setenv.sh in CATALINA_BASE/bin to keep your customizations separate. 25 | # 26 | # CATALINA_HOME May point at your Catalina "build" directory. 27 | # 28 | # CATALINA_BASE (Optional) Base directory for resolving dynamic portions 29 | # of a Catalina installation. If not present, resolves to 30 | # the same directory that CATALINA_HOME points to. 31 | # 32 | # CATALINA_OUT (Optional) Full path to a file where stdout and stderr 33 | # will be redirected. 34 | # Default is $CATALINA_BASE/logs/catalina.out 35 | # 36 | # CATALINA_OPTS (Optional) Java runtime options used when the "start", 37 | # "run" or "debug" command is executed. 38 | # Include here and not in JAVA_OPTS all options, that should 39 | # only be used by Tomcat itself, not by the stop process, 40 | # the version command etc. 41 | # Examples are heap size, GC logging, JMX ports etc. 42 | # 43 | # CATALINA_TMPDIR (Optional) Directory path location of temporary directory 44 | # the JVM should use (java.io.tmpdir). Defaults to 45 | # $CATALINA_BASE/temp. 46 | # 47 | # JAVA_HOME Must point at your Java Development Kit installation. 48 | # Required to run the with the "debug" argument. 49 | # 50 | # JRE_HOME Must point at your Java Runtime installation. 51 | # Defaults to JAVA_HOME if empty. If JRE_HOME and JAVA_HOME 52 | # are both set, JRE_HOME is used. 53 | # 54 | # JAVA_OPTS (Optional) Java runtime options used when any command 55 | # is executed. 56 | # Include here and not in CATALINA_OPTS all options, that 57 | # should be used by Tomcat and also by the stop process, 58 | # the version command etc. 59 | # Most options should go into CATALINA_OPTS. 60 | # 61 | # JAVA_ENDORSED_DIRS (Optional) Lists of of colon separated directories 62 | # containing some jars in order to allow replacement of APIs 63 | # created outside of the JCP (i.e. DOM and SAX from W3C). 64 | # It can also be used to update the XML parser implementation. 65 | # Defaults to $CATALINA_HOME/endorsed. 66 | # 67 | # JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda start" 68 | # command is executed. The default is "dt_socket". 69 | # 70 | # JPDA_ADDRESS (Optional) Java runtime options used when the "jpda start" 71 | # command is executed. The default is localhost:8000. 72 | # 73 | # JPDA_SUSPEND (Optional) Java runtime options used when the "jpda start" 74 | # command is executed. Specifies whether JVM should suspend 75 | # execution immediately after startup. Default is "n". 76 | # 77 | # JPDA_OPTS (Optional) Java runtime options used when the "jpda start" 78 | # command is executed. If used, JPDA_TRANSPORT, JPDA_ADDRESS, 79 | # and JPDA_SUSPEND are ignored. Thus, all required jpda 80 | # options MUST be specified. The default is: 81 | # 82 | # -agentlib:jdwp=transport=$JPDA_TRANSPORT, 83 | # address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND 84 | # 85 | # CATALINA_PID (Optional) Path of the file which should contains the pid 86 | # of the catalina startup java process, when start (fork) is 87 | # used 88 | # 89 | # LOGGING_CONFIG (Optional) Override Tomcat's logging config file 90 | # Example (all one line) 91 | # LOGGING_CONFIG="-Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties" 92 | # 93 | # LOGGING_MANAGER (Optional) Override Tomcat's logging manager 94 | # Example (all one line) 95 | # LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" 96 | # ----------------------------------------------------------------------------- 97 | 98 | JAVA_OPTS="-XX:PermSize=128m -Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom" 99 | 100 | # OS specific support. $var _must_ be set to either true or false. 101 | cygwin=false 102 | darwin=false 103 | os400=false 104 | case "`uname`" in 105 | CYGWIN*) cygwin=true;; 106 | Darwin*) darwin=true;; 107 | OS400*) os400=true;; 108 | esac 109 | 110 | # resolve links - $0 may be a softlink 111 | PRG="$0" 112 | 113 | while [ -h "$PRG" ]; do 114 | ls=`ls -ld "$PRG"` 115 | link=`expr "$ls" : '.*-> \(.*\)$'` 116 | if expr "$link" : '/.*' > /dev/null; then 117 | PRG="$link" 118 | else 119 | PRG=`dirname "$PRG"`/"$link" 120 | fi 121 | done 122 | 123 | # Get standard environment variables 124 | PRGDIR=`dirname "$PRG"` 125 | 126 | # Only set CATALINA_HOME if not already set 127 | [ -z "$CATALINA_HOME" ] && CATALINA_HOME=`cd "$PRGDIR/.." >/dev/null; pwd` 128 | 129 | # Copy CATALINA_BASE from CATALINA_HOME if not already set 130 | [ -z "$CATALINA_BASE" ] && CATALINA_BASE="$CATALINA_HOME" 131 | 132 | # Ensure that neither CATALINA_HOME nor CATALINA_BASE contains a colon 133 | # as this is used as the separator in the classpath and Java provides no 134 | # mechanism for escaping if the same character appears in the path. 135 | case $CATALINA_HOME in 136 | *:*) echo "Using CATALINA_HOME: $CATALINA_HOME"; 137 | echo "Unable to start as CATALINA_HOME contains a colon (:) character"; 138 | exit 1; 139 | esac 140 | case $CATALINA_BASE in 141 | *:*) echo "Using CATALINA_BASE: $CATALINA_BASE"; 142 | echo "Unable to start as CATALINA_BASE contains a colon (:) character"; 143 | exit 1; 144 | esac 145 | 146 | # Ensure that any user defined CLASSPATH variables are not used on startup, 147 | # but allow them to be specified in setenv.sh, in rare case when it is needed. 148 | CLASSPATH= 149 | 150 | if [ -r "$CATALINA_BASE/bin/setenv.sh" ]; then 151 | . "$CATALINA_BASE/bin/setenv.sh" 152 | elif [ -r "$CATALINA_HOME/bin/setenv.sh" ]; then 153 | . "$CATALINA_HOME/bin/setenv.sh" 154 | fi 155 | 156 | # For Cygwin, ensure paths are in UNIX format before anything is touched 157 | if $cygwin; then 158 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 159 | [ -n "$JRE_HOME" ] && JRE_HOME=`cygpath --unix "$JRE_HOME"` 160 | [ -n "$CATALINA_HOME" ] && CATALINA_HOME=`cygpath --unix "$CATALINA_HOME"` 161 | [ -n "$CATALINA_BASE" ] && CATALINA_BASE=`cygpath --unix "$CATALINA_BASE"` 162 | [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 163 | fi 164 | 165 | # For OS400 166 | if $os400; then 167 | # Set job priority to standard for interactive (interactive - 6) by using 168 | # the interactive priority - 6, the helper threads that respond to requests 169 | # will be running at the same priority as interactive jobs. 170 | COMMAND='chgjob job('$JOBNAME') runpty(6)' 171 | system $COMMAND 172 | 173 | # Enable multi threading 174 | export QIBM_MULTI_THREADED=Y 175 | fi 176 | 177 | # Get standard Java environment variables 178 | if $os400; then 179 | # -r will Only work on the os400 if the files are: 180 | # 1. owned by the user 181 | # 2. owned by the PRIMARY group of the user 182 | # this will not work if the user belongs in secondary groups 183 | . "$CATALINA_HOME"/bin/setclasspath.sh 184 | else 185 | if [ -r "$CATALINA_HOME"/bin/setclasspath.sh ]; then 186 | . "$CATALINA_HOME"/bin/setclasspath.sh 187 | else 188 | echo "Cannot find $CATALINA_HOME/bin/setclasspath.sh" 189 | echo "This file is needed to run this program" 190 | exit 1 191 | fi 192 | fi 193 | 194 | # Add on extra jar files to CLASSPATH 195 | if [ ! -z "$CLASSPATH" ] ; then 196 | CLASSPATH="$CLASSPATH": 197 | fi 198 | CLASSPATH="$CLASSPATH""$CATALINA_HOME"/bin/bootstrap.jar 199 | 200 | if [ -z "$CATALINA_OUT" ] ; then 201 | CATALINA_OUT="$CATALINA_BASE"/logs/catalina.out 202 | fi 203 | 204 | if [ -z "$CATALINA_TMPDIR" ] ; then 205 | # Define the java.io.tmpdir to use for Catalina 206 | CATALINA_TMPDIR="$CATALINA_BASE"/temp 207 | fi 208 | 209 | # Add tomcat-juli.jar to classpath 210 | # tomcat-juli.jar can be over-ridden per instance 211 | if [ -r "$CATALINA_BASE/bin/tomcat-juli.jar" ] ; then 212 | CLASSPATH=$CLASSPATH:$CATALINA_BASE/bin/tomcat-juli.jar 213 | else 214 | CLASSPATH=$CLASSPATH:$CATALINA_HOME/bin/tomcat-juli.jar 215 | fi 216 | 217 | # Bugzilla 37848: When no TTY is available, don't output to console 218 | have_tty=0 219 | if [ "`tty`" != "not a tty" ]; then 220 | have_tty=1 221 | fi 222 | 223 | # For Cygwin, switch paths to Windows format before running java 224 | if $cygwin; then 225 | JAVA_HOME=`cygpath --absolute --windows "$JAVA_HOME"` 226 | JRE_HOME=`cygpath --absolute --windows "$JRE_HOME"` 227 | CATALINA_HOME=`cygpath --absolute --windows "$CATALINA_HOME"` 228 | CATALINA_BASE=`cygpath --absolute --windows "$CATALINA_BASE"` 229 | CATALINA_TMPDIR=`cygpath --absolute --windows "$CATALINA_TMPDIR"` 230 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 231 | JAVA_ENDORSED_DIRS=`cygpath --path --windows "$JAVA_ENDORSED_DIRS"` 232 | fi 233 | 234 | # Set juli LogManager config file if it is present and an override has not been issued 235 | if [ -z "$LOGGING_CONFIG" ]; then 236 | if [ -r "$CATALINA_BASE"/conf/logging.properties ]; then 237 | LOGGING_CONFIG="-Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties" 238 | else 239 | # Bugzilla 45585 240 | LOGGING_CONFIG="-Dnop" 241 | fi 242 | fi 243 | 244 | if [ -z "$LOGGING_MANAGER" ]; then 245 | LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" 246 | fi 247 | 248 | # Uncomment the following line to make the umask available when using the 249 | # org.apache.catalina.security.SecurityListener 250 | #JAVA_OPTS="$JAVA_OPTS -Dorg.apache.catalina.security.SecurityListener.UMASK=`umask`" 251 | 252 | # ----- Execute The Requested Command ----------------------------------------- 253 | 254 | # Bugzilla 37848: only output this if we have a TTY 255 | if [ $have_tty -eq 1 ]; then 256 | echo "Using CATALINA_BASE: $CATALINA_BASE" 257 | echo "Using CATALINA_HOME: $CATALINA_HOME" 258 | echo "Using CATALINA_TMPDIR: $CATALINA_TMPDIR" 259 | if [ "$1" = "debug" ] ; then 260 | echo "Using JAVA_HOME: $JAVA_HOME" 261 | else 262 | echo "Using JRE_HOME: $JRE_HOME" 263 | fi 264 | echo "Using CLASSPATH: $CLASSPATH" 265 | if [ ! -z "$CATALINA_PID" ]; then 266 | echo "Using CATALINA_PID: $CATALINA_PID" 267 | fi 268 | fi 269 | 270 | if [ "$1" = "jpda" ] ; then 271 | if [ -z "$JPDA_TRANSPORT" ]; then 272 | JPDA_TRANSPORT="dt_socket" 273 | fi 274 | if [ -z "$JPDA_ADDRESS" ]; then 275 | JPDA_ADDRESS="localhost:8000" 276 | fi 277 | if [ -z "$JPDA_SUSPEND" ]; then 278 | JPDA_SUSPEND="n" 279 | fi 280 | if [ -z "$JPDA_OPTS" ]; then 281 | JPDA_OPTS="-agentlib:jdwp=transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND" 282 | fi 283 | CATALINA_OPTS="$JPDA_OPTS $CATALINA_OPTS" 284 | shift 285 | fi 286 | 287 | if [ "$1" = "debug" ] ; then 288 | if $os400; then 289 | echo "Debug command not available on OS400" 290 | exit 1 291 | else 292 | shift 293 | if [ "$1" = "-security" ] ; then 294 | if [ $have_tty -eq 1 ]; then 295 | echo "Using Security Manager" 296 | fi 297 | shift 298 | exec "$_RUNJDB" "$LOGGING_CONFIG" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ 299 | -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ 300 | -sourcepath "$CATALINA_HOME"/../../java \ 301 | -Djava.security.manager \ 302 | -Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \ 303 | -Dcatalina.base="$CATALINA_BASE" \ 304 | -Dcatalina.home="$CATALINA_HOME" \ 305 | -Djava.io.tmpdir="$CATALINA_TMPDIR" \ 306 | org.apache.catalina.startup.Bootstrap "$@" start 307 | else 308 | exec "$_RUNJDB" "$LOGGING_CONFIG" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ 309 | -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ 310 | -sourcepath "$CATALINA_HOME"/../../java \ 311 | -Dcatalina.base="$CATALINA_BASE" \ 312 | -Dcatalina.home="$CATALINA_HOME" \ 313 | -Djava.io.tmpdir="$CATALINA_TMPDIR" \ 314 | org.apache.catalina.startup.Bootstrap "$@" start 315 | fi 316 | fi 317 | 318 | elif [ "$1" = "run" ]; then 319 | 320 | shift 321 | if [ "$1" = "-security" ] ; then 322 | if [ $have_tty -eq 1 ]; then 323 | echo "Using Security Manager" 324 | fi 325 | shift 326 | eval exec "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ 327 | -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ 328 | -Djava.security.manager \ 329 | -Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \ 330 | -Dcatalina.base="\"$CATALINA_BASE\"" \ 331 | -Dcatalina.home="\"$CATALINA_HOME\"" \ 332 | -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ 333 | org.apache.catalina.startup.Bootstrap "$@" start 334 | else 335 | eval exec "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ 336 | -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ 337 | -Dcatalina.base="\"$CATALINA_BASE\"" \ 338 | -Dcatalina.home="\"$CATALINA_HOME\"" \ 339 | -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ 340 | org.apache.catalina.startup.Bootstrap "$@" start 341 | fi 342 | 343 | elif [ "$1" = "start" ] ; then 344 | 345 | if [ ! -z "$CATALINA_PID" ]; then 346 | if [ -f "$CATALINA_PID" ]; then 347 | if [ -s "$CATALINA_PID" ]; then 348 | echo "Existing PID file found during start." 349 | if [ -r "$CATALINA_PID" ]; then 350 | PID=`cat "$CATALINA_PID"` 351 | ps -p $PID >/dev/null 2>&1 352 | if [ $? -eq 0 ] ; then 353 | echo "Tomcat appears to still be running with PID $PID. Start aborted." 354 | echo "If the following process is not a Tomcat process, remove the PID file and try again:" 355 | ps -f -p $PID 356 | exit 1 357 | else 358 | echo "Removing/clearing stale PID file." 359 | rm -f "$CATALINA_PID" >/dev/null 2>&1 360 | if [ $? != 0 ]; then 361 | if [ -w "$CATALINA_PID" ]; then 362 | cat /dev/null > "$CATALINA_PID" 363 | else 364 | echo "Unable to remove or clear stale PID file. Start aborted." 365 | exit 1 366 | fi 367 | fi 368 | fi 369 | else 370 | echo "Unable to read PID file. Start aborted." 371 | exit 1 372 | fi 373 | else 374 | rm -f "$CATALINA_PID" >/dev/null 2>&1 375 | if [ $? != 0 ]; then 376 | if [ ! -w "$CATALINA_PID" ]; then 377 | echo "Unable to remove or write to empty PID file. Start aborted." 378 | exit 1 379 | fi 380 | fi 381 | fi 382 | fi 383 | fi 384 | 385 | shift 386 | touch "$CATALINA_OUT" 387 | if [ "$1" = "-security" ] ; then 388 | if [ $have_tty -eq 1 ]; then 389 | echo "Using Security Manager" 390 | fi 391 | shift 392 | eval "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ 393 | -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ 394 | -Djava.security.manager \ 395 | -Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \ 396 | -Dcatalina.base="\"$CATALINA_BASE\"" \ 397 | -Dcatalina.home="\"$CATALINA_HOME\"" \ 398 | -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ 399 | org.apache.catalina.startup.Bootstrap "$@" start \ 400 | >> "$CATALINA_OUT" 2>&1 "&" 401 | 402 | else 403 | eval "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ 404 | -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ 405 | -Dcatalina.base="\"$CATALINA_BASE\"" \ 406 | -Dcatalina.home="\"$CATALINA_HOME\"" \ 407 | -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ 408 | org.apache.catalina.startup.Bootstrap "$@" start \ 409 | >> "$CATALINA_OUT" 2>&1 "&" 410 | 411 | fi 412 | 413 | if [ ! -z "$CATALINA_PID" ]; then 414 | echo $! > "$CATALINA_PID" 415 | fi 416 | 417 | echo "Tomcat started." 418 | 419 | elif [ "$1" = "stop" ] ; then 420 | 421 | shift 422 | 423 | SLEEP=5 424 | if [ ! -z "$1" ]; then 425 | echo $1 | grep "[^0-9]" >/dev/null 2>&1 426 | if [ $? -gt 0 ]; then 427 | SLEEP=$1 428 | shift 429 | fi 430 | fi 431 | 432 | FORCE=0 433 | if [ "$1" = "-force" ]; then 434 | shift 435 | FORCE=1 436 | fi 437 | 438 | if [ ! -z "$CATALINA_PID" ]; then 439 | if [ -f "$CATALINA_PID" ]; then 440 | if [ -s "$CATALINA_PID" ]; then 441 | kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 442 | if [ $? -gt 0 ]; then 443 | echo "PID file found but no matching process was found. Stop aborted." 444 | exit 1 445 | fi 446 | else 447 | echo "PID file is empty and has been ignored." 448 | fi 449 | else 450 | echo "\$CATALINA_PID was set but the specified file does not exist. Is Tomcat running? Stop aborted." 451 | exit 1 452 | fi 453 | fi 454 | 455 | eval "\"$_RUNJAVA\"" $LOGGING_MANAGER $JAVA_OPTS \ 456 | -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ 457 | -Dcatalina.base="\"$CATALINA_BASE\"" \ 458 | -Dcatalina.home="\"$CATALINA_HOME\"" \ 459 | -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ 460 | org.apache.catalina.startup.Bootstrap "$@" stop 461 | 462 | # stop failed. Shutdown port disabled? Try a normal kill. 463 | if [ $? != 0 ]; then 464 | if [ ! -z "$CATALINA_PID" ]; then 465 | echo "The stop command failed. Attempting to signal the process to stop through OS signal." 466 | kill -15 `cat "$CATALINA_PID"` >/dev/null 2>&1 467 | fi 468 | fi 469 | 470 | if [ ! -z "$CATALINA_PID" ]; then 471 | if [ -f "$CATALINA_PID" ]; then 472 | while [ $SLEEP -ge 0 ]; do 473 | kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 474 | if [ $? -gt 0 ]; then 475 | rm -f "$CATALINA_PID" >/dev/null 2>&1 476 | if [ $? != 0 ]; then 477 | if [ -w "$CATALINA_PID" ]; then 478 | cat /dev/null > "$CATALINA_PID" 479 | # If Tomcat has stopped don't try and force a stop with an empty PID file 480 | FORCE=0 481 | else 482 | echo "The PID file could not be removed or cleared." 483 | fi 484 | fi 485 | echo "Tomcat stopped." 486 | break 487 | fi 488 | if [ $SLEEP -gt 0 ]; then 489 | sleep 1 490 | fi 491 | if [ $SLEEP -eq 0 ]; then 492 | echo "Tomcat did not stop in time." 493 | if [ $FORCE -eq 0 ]; then 494 | echo "PID file was not removed." 495 | fi 496 | echo "To aid diagnostics a thread dump has been written to standard out." 497 | kill -3 `cat "$CATALINA_PID"` 498 | fi 499 | SLEEP=`expr $SLEEP - 1 ` 500 | done 501 | fi 502 | fi 503 | 504 | KILL_SLEEP_INTERVAL=5 505 | if [ $FORCE -eq 1 ]; then 506 | if [ -z "$CATALINA_PID" ]; then 507 | echo "Kill failed: \$CATALINA_PID not set" 508 | else 509 | if [ -f "$CATALINA_PID" ]; then 510 | PID=`cat "$CATALINA_PID"` 511 | echo "Killing Tomcat with the PID: $PID" 512 | kill -9 $PID 513 | while [ $KILL_SLEEP_INTERVAL -ge 0 ]; do 514 | kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 515 | if [ $? -gt 0 ]; then 516 | rm -f "$CATALINA_PID" >/dev/null 2>&1 517 | if [ $? != 0 ]; then 518 | if [ -w "$CATALINA_PID" ]; then 519 | cat /dev/null > "$CATALINA_PID" 520 | else 521 | echo "The PID file could not be removed." 522 | fi 523 | fi 524 | echo "The Tomcat process has been killed." 525 | break 526 | fi 527 | if [ $KILL_SLEEP_INTERVAL -gt 0 ]; then 528 | sleep 1 529 | fi 530 | KILL_SLEEP_INTERVAL=`expr $KILL_SLEEP_INTERVAL - 1 ` 531 | done 532 | if [ $KILL_SLEEP_INTERVAL -lt 0 ]; then 533 | echo "Tomcat has not been killed completely yet. The process might be waiting on some system call or might be UNINTERRUPTIBLE." 534 | fi 535 | fi 536 | fi 537 | fi 538 | 539 | elif [ "$1" = "configtest" ] ; then 540 | 541 | eval "\"$_RUNJAVA\"" $LOGGING_MANAGER $JAVA_OPTS \ 542 | -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ 543 | -Dcatalina.base="\"$CATALINA_BASE\"" \ 544 | -Dcatalina.home="\"$CATALINA_HOME\"" \ 545 | -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ 546 | org.apache.catalina.startup.Bootstrap configtest 547 | result=$? 548 | if [ $result -ne 0 ]; then 549 | echo "Configuration error detected!" 550 | fi 551 | exit $result 552 | 553 | elif [ "$1" = "version" ] ; then 554 | 555 | "$_RUNJAVA" \ 556 | -classpath "$CATALINA_HOME/lib/catalina.jar" \ 557 | org.apache.catalina.util.ServerInfo 558 | 559 | else 560 | 561 | echo "Usage: catalina.sh ( commands ... )" 562 | echo "commands:" 563 | if $os400; then 564 | echo " debug Start Catalina in a debugger (not available on OS400)" 565 | echo " debug -security Debug Catalina with a security manager (not available on OS400)" 566 | else 567 | echo " debug Start Catalina in a debugger" 568 | echo " debug -security Debug Catalina with a security manager" 569 | fi 570 | echo " jpda start Start Catalina under JPDA debugger" 571 | echo " run Start Catalina in the current window" 572 | echo " run -security Start in the current window with security manager" 573 | echo " start Start Catalina in a separate window" 574 | echo " start -security Start in a separate window with security manager" 575 | echo " stop Stop Catalina, waiting up to 5 seconds for the process to end" 576 | echo " stop n Stop Catalina, waiting up to n seconds for the process to end" 577 | echo " stop -force Stop Catalina, wait up to 5 seconds and then use kill -KILL if still running" 578 | echo " stop n -force Stop Catalina, wait up to n seconds and then use kill -KILL if still running" 579 | echo " configtest Run a basic syntax check on server.xml - check exit code for result" 580 | echo " version What version of tomcat are you running?" 581 | echo "Note: Waiting for the process to end and use of the -force option require that \$CATALINA_PID is defined" 582 | exit 1 583 | 584 | fi 585 | -------------------------------------------------------------------------------- /docker/shiny-tomcat8-proxied/files/server.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /docker/shiny/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rocker/r-ver:3.5.0 2 | 3 | LABEL maintainer="Scott Came (scottcame10@gmail.com)" \ 4 | org.label-schema.description="Image with shiny-server 1.5.7.907 and R 3.5.0 that supports SAML assertions in session" \ 5 | org.label-schema.vcs-url="https://github.com/scottcame/shiny-microservice-demo/docker/shiny" \ 6 | license="AGPLv3" 7 | 8 | # Underlying Shiny Server software is licensed under the GNU Affero Public License. 9 | # See https://github.com/rstudio/shiny-server/blob/master/COPYING for details. 10 | 11 | # This program is free software: you can redistribute it and/or modify 12 | # it under the terms of the GNU Affero General Public License as published by 13 | # the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU Affero General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU Affero General Public License 22 | # along with this program. If not, see . 23 | 24 | # We need to build to a specific version of shiny-server, since we will be editing some of the node js files 25 | # This also gives us the opportunity to include some additional libraries/packages that we need 26 | 27 | RUN apt-get update && \ 28 | apt-get install -y net-tools libssl-dev libxml2-dev gdebi-core pandoc pandoc-citeproc libcurl4-gnutls-dev libcairo2-dev libxt-dev curl libmariadbclient-dev && \ 29 | cd /tmp && \ 30 | curl -O https://download3.rstudio.org/ubuntu-14.04/x86_64/shiny-server-1.5.7.907-amd64.deb && \ 31 | R -e 'install.packages(c("xml2", "lubridate", "tidyverse", "shiny", "rmarkdown", "RMariaDB"), repos="https://cran.rstudio.com/")' && \ 32 | gdebi -n shiny-server-1.5.7.907-amd64.deb && \ 33 | rm shiny-server-1.5.7.907-amd64.deb && rm -rf /var/lib/apt/lists/* 34 | 35 | COPY files/shiny-server.conf /etc/shiny-server/ 36 | 37 | # Here we apply edits to pass around whitelisted headers defined in files/header-whitelist.js 38 | # With some effort, this could be refactored to support a config parameter, but this is the minimal thing needed to meet the objectives of the demo 39 | # These edits were based upon those in this PR: https://github.com/rstudio/shiny-server/pull/257 40 | 41 | RUN sed -i \ 42 | -e "17c\ exitPromise, kill, headers) {" \ 43 | -e "25i\ this.headers=headers;" \ 44 | /opt/shiny-server/lib/worker/app-worker-handle.js 45 | 46 | RUN sed -i \ 47 | -e "23ivar whitelistedHeaders = require('../header-whitelist').headerWhitelist;" \ 48 | -e "121i\ var headers = _.pick(conn.headers, whitelistedHeaders);" \ 49 | -e "129c\ wrk = schedulerRegistry.getWorker(appSpec, 'ws', null, headers);" \ 50 | -e "167c\ wsClient = appWorkerHandle.endpoint.createWebSocketClient(pathInfo, headers);" \ 51 | /opt/shiny-server/lib/proxy/sockjs.js 52 | 53 | RUN sed -i \ 54 | -e "25ivar whitelistedHeaders = require('../header-whitelist').headerWhitelist;" \ 55 | -e "138i\ var headers = _.pick(req.headers, whitelistedHeaders);" \ 56 | -e "144c\ wrk = schedulerRegistry.getWorker(appSpec, pathname, worker, headers);" \ 57 | /opt/shiny-server/lib/proxy/http.js 58 | 59 | RUN sed -i \ 60 | -e "66c\ this.getWorker = function(appSpec, url, worker, headers) {" \ 61 | -e "77c\ return this.\$schedulers[key].acquireWorker(appSpec, url, worker, headers);" \ 62 | /opt/shiny-server/lib/scheduler/scheduler-registry.js 63 | 64 | RUN sed -i \ 65 | -e "226c\ _.bind(appWorker.kill, appWorker, workerData.headers));" \ 66 | /opt/shiny-server/lib/scheduler/scheduler.js 67 | 68 | RUN sed -i \ 69 | -e "34c\ this.acquireWorker = function(appSpec, url, worker, headers) {" \ 70 | -e "71c\ return this.spawnWorker(appSpec, {headers: headers});" \ 71 | /opt/shiny-server/lib/scheduler/simple-scheduler.js 72 | 73 | COPY files/header-whitelist.js /opt/shiny-server/lib/ 74 | 75 | # We also need to modify the hardcoded list of passed-thru headers in sockjs, to add the one that Shibboleth SP adds to each request containing 76 | # the address at which the user's assertion is available 77 | 78 | RUN sed -i '169i ref.push("shib-assertion-01");' /opt/shiny-server/node_modules/sockjs/lib/transport.js 79 | 80 | # uncomment if you want all the shiny examples available 81 | # RUN cp -R /usr/local/lib/R/site-library/shiny/examples/* /srv/shiny-server/ 82 | 83 | RUN mkdir -p /srv/shiny-server/hostinfo 84 | RUN mkdir -p /srv/shiny-server/saml 85 | 86 | COPY files/hostinfo/app.R /srv/shiny-server/hostinfo/ 87 | COPY files/saml/app.R /srv/shiny-server/saml/ 88 | COPY files/db-access/app.R /srv/shiny-server/db-access/ 89 | COPY files/db-access-secure/app.R /srv/shiny-server/db-access-secure/ 90 | 91 | RUN mkdir -p /var/log/shiny-server 92 | 93 | # If docker exec-ing into a running container, 99 times out of 100 you want to be in the app logs directory, so here you go... 94 | WORKDIR /var/log/shiny-server 95 | 96 | CMD ["/opt/shiny-server/bin/shiny-server"] 97 | -------------------------------------------------------------------------------- /docker/shiny/files/db-access-secure/app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(tidyverse) 3 | library(RMariaDB) 4 | library(xml2) 5 | 6 | DB_HOST = 'demo-mariadb' 7 | 8 | ui <- fluidPage( 9 | h3(textOutput('tableName', inline=TRUE), ":"), tableOutput('tt') 10 | ) 11 | 12 | server <- function(input, output, session) { 13 | 14 | assertion <- session$request$HTTP_SHIB_ASSERTION_01 15 | # ignoring SSL errors is ok. In a Docker context, there is no way to get a spoofed url 16 | a <- read_xml(httr::GET(assertion, config = httr::config(ssl_verifyhost = FALSE, ssl_verifypeer=FALSE))) 17 | org <- a %>% xml_find_first('/saml2:Assertion/saml2:AttributeStatement/saml2:Attribute[@Name="o"]/saml2:AttributeValue') %>% xml_text() 18 | 19 | orgType <- gsub(x=org, pattern='.+([A-Z])$', replacement='\\1') 20 | output$tableName <- renderText(paste0('Table t1', orgType)) 21 | 22 | conn <- dbConnect(MariaDB(), host=DB_HOST, dbname='demo1', user='root') 23 | tt <- dbReadTable(conn, paste0('t1', orgType)) 24 | output$tt <- renderTable(tt) 25 | dbDisconnect(conn) 26 | 27 | } 28 | 29 | shinyApp(ui, server) 30 | -------------------------------------------------------------------------------- /docker/shiny/files/db-access/app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(tidyverse) 3 | library(RMariaDB) 4 | 5 | DB_HOST = 'demo-mariadb' 6 | 7 | ui <- fluidPage( 8 | h3('Table T1A: '), tableOutput('t1A'), 9 | h3('Table T1B: '), tableOutput('t1B') 10 | ) 11 | 12 | server <- function(input, output, session) { 13 | 14 | conn <- dbConnect(MariaDB(), host=DB_HOST, dbname='demo1', user='root') 15 | t1A <- dbReadTable(conn, 't1A') 16 | output$t1A <- renderTable(t1A) 17 | t1B <- dbReadTable(conn, 't1B') 18 | output$t1B <- renderTable(t1B) 19 | dbDisconnect(conn) 20 | 21 | } 22 | 23 | shinyApp(ui, server) 24 | -------------------------------------------------------------------------------- /docker/shiny/files/header-whitelist.js: -------------------------------------------------------------------------------- 1 | exports.headerWhitelist = ['user-agent', 'shib-assertion-01']; 2 | -------------------------------------------------------------------------------- /docker/shiny/files/hostinfo/app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(tidyverse) 3 | 4 | ui <- fluidPage( 5 | h5('Server Info: '), verbatimTextOutput("info") 6 | ) 7 | 8 | server <- function(input, output, session) { 9 | 10 | hostname <- Sys.info()['nodename'] 11 | ip <- 'Unknown' 12 | 13 | os <- Sys.info()['sysname'] 14 | 15 | interface <- 'eth0' 16 | command <- '/sbin/ifconfig' 17 | 18 | if (os == 'Darwin') { 19 | interface <- 'en0' 20 | command <- 'ifconfig' 21 | } 22 | 23 | ifconfigOutput <- trimws(system(paste0(command, ' ', interface), intern=TRUE)) 24 | s <- ifconfigOutput[grepl(x=ifconfigOutput, pattern='^inet ')] 25 | ip <- gsub(x=s, pattern='inet [^0-9]*((?:[0-9]{1,3}\\.){3}(?:[0-9]{1,3})).+', replacement='\\1', perl=TRUE) 26 | 27 | output$info <- renderText({ 28 | paste0('Hostname: ', hostname, ", IP address: ", ip) 29 | }) 30 | 31 | } 32 | 33 | shinyApp(ui, server) 34 | -------------------------------------------------------------------------------- /docker/shiny/files/saml/app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(xml2) 3 | library(lubridate) 4 | library(tidyverse) 5 | 6 | parseAssertion <- function(assertionUrl) { 7 | 8 | # ignoring SSL errors is ok. In a Docker context, there is no way to get a spoofed url 9 | a <- read_xml(httr::GET(assertionUrl, config = httr::config(ssl_verifyhost = FALSE, ssl_verifypeer=FALSE))) 10 | 11 | ret <- list() 12 | 13 | ret$IssuedDateTime <- a %>% xml_find_first('/saml2:Assertion/@IssueInstant') %>% xml_text() %>% as_datetime() 14 | ret$Issuer <- a %>% xml_find_first('/saml2:Assertion/saml2:Issuer') %>% xml_text() 15 | ret$ExpirationDateTime <- a %>% xml_find_first('/saml2:Assertion/saml2:Conditions/@NotOnOrAfter') %>% xml_text() %>% as_datetime() 16 | ret$AuthenticationDateTime <- a %>% xml_find_first('/saml2:Assertion/saml2:AuthnStatement/@AuthnInstant') %>% xml_text() %>% as_datetime() 17 | ret$AuthenticationContextClass <- a %>% xml_find_first('/saml2:Assertion/saml2:AuthnStatement/saml2:AuthnContext/saml2:AuthnContextClassRef') %>% xml_text() 18 | 19 | ret$Attributes <- map_df(xml_find_all(a, '//saml2:Attribute'), function(node) { 20 | tibble(Attribute=xml_attr(node, 'Name'), Value=xml_text(xml_find_first(node, 'saml2:AttributeValue'))) 21 | }) 22 | 23 | ret 24 | 25 | } 26 | 27 | ui <- fluidPage( 28 | h5('Server Info: '), verbatimTextOutput("info"), 29 | # h5('Shib url: '), verbatimTextOutput("shib"), 30 | h5('SAML Authentication Information: '), uiOutput('bList'), 31 | h5('Assertion Attributes:'), tableOutput('assertionAttributes') 32 | ) 33 | 34 | server <- function(input, output, session) { 35 | 36 | hostname <- Sys.info()['nodename'] 37 | ip <- 'Unknown' 38 | 39 | os <- Sys.info()['sysname'] 40 | 41 | interface <- 'eth0' 42 | command <- '/sbin/ifconfig' 43 | 44 | if (os == 'Darwin') { 45 | interface <- 'en0' 46 | command <- 'ifconfig' 47 | } 48 | 49 | ifconfigOutput <- trimws(system(paste0(command, ' ', interface), intern=TRUE)) 50 | s <- ifconfigOutput[grepl(x=ifconfigOutput, pattern='^inet ')] 51 | ip <- gsub(x=s, pattern='inet [^0-9]*((?:[0-9]{1,3}\\.){3}(?:[0-9]{1,3})).+', replacement='\\1', perl=TRUE) 52 | 53 | output$info <- renderText({ 54 | paste0('Hostname: ', hostname, ", IP address: ", ip) 55 | }) 56 | 57 | #output$shib <- renderText({ 58 | # session$request$HTTP_SHIB_ASSERTION_01 59 | #}) 60 | 61 | assertion <- session$request$HTTP_SHIB_ASSERTION_01 62 | 63 | if (is.null(assertion)) { 64 | 65 | output$bList <- renderUI({tags$p(tags$span('No authentication info: shiny is not running in a SAML context.', style='font-family: italic'))}) 66 | output$assertionAttributes <- renderUI({tags$p(tags$span('No assertion attributes: shiny is not running in a SAML context.', style='font-family: italic'))}) 67 | 68 | } else { 69 | 70 | assertionList <- parseAssertion(assertion) 71 | 72 | output$bList <- renderUI({ 73 | tags$ul( 74 | tags$li(paste0('Assertion Issued At: ', assertionList$IssuedDateTime)), 75 | tags$li(paste0('Assertion Issued By: ', assertionList$Issuer)), 76 | tags$li(paste0('Assertion Expires At: ', assertionList$ExpirationDateTime)), 77 | tags$li(paste0('Authentication Occurred At: ', assertionList$AuthenticationDateTime)), 78 | tags$li(paste0('Authentication Class: ', assertionList$AuthenticationContextClass)) 79 | ) 80 | }) 81 | 82 | output$assertionAttributes <- renderTable(assertionList$Attributes) 83 | 84 | } 85 | 86 | } 87 | 88 | shinyApp(ui, server) 89 | -------------------------------------------------------------------------------- /docker/shiny/files/shiny-server.conf: -------------------------------------------------------------------------------- 1 | # Instruct Shiny Server to run applications as the user "shiny" 2 | run_as shiny; 3 | 4 | # Define a server that listens on port 3838 5 | server { 6 | listen 3838; 7 | 8 | # Define a location at the base URL 9 | location / { 10 | 11 | # disable_protocols websocket; 12 | 13 | # Host the directory of Shiny Apps stored in this directory 14 | site_dir /srv/shiny-server; 15 | 16 | # Log all Shiny output to files in this directory 17 | log_dir /var/log/shiny-server; 18 | 19 | # When a user visits the base URL rather than a particular application, 20 | # an index of the applications available in this directory will be shown. 21 | directory_index on; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docker/tidyverse-mariadb/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rocker/tidyverse:3.5 2 | 3 | LABEL maintainer="Scott Came (scottcame10@gmail.com)" \ 4 | org.label-schema.description="Image that extends the rocker tidyverse image to include support for MariaDB" \ 5 | org.label-schema.vcs-url="https://github.com/scottcame/shiny-microservice-demo/docker/tidyverse-mariadb" 6 | 7 | RUN apt-get update && apt-get install -y libmariadbclient-dev && R -e 'install.packages("RMariaDB")' 8 | -------------------------------------------------------------------------------- /shiny-app/shiny/db-access-secure/app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(tidyverse) 3 | library(RMariaDB) 4 | library(xml2) 5 | 6 | DB_HOST = 'mariadb' 7 | 8 | ui <- fluidPage( 9 | h3(textOutput('tableName', inline=TRUE), ":"), tableOutput('tt') 10 | ) 11 | 12 | server <- function(input, output, session) { 13 | 14 | assertion <- session$request$HTTP_SHIB_ASSERTION_01 15 | # ignoring SSL errors is ok. In a Docker context, there is no way to get a spoofed url 16 | a <- read_xml(httr::GET(assertion, config = httr::config(ssl_verifyhost = FALSE, ssl_verifypeer=FALSE))) 17 | org <- a %>% xml_find_first('/saml2:Assertion/saml2:AttributeStatement/saml2:Attribute[@Name="o"]/saml2:AttributeValue') %>% xml_text() 18 | 19 | orgType <- gsub(x=org, pattern='.+([A-Z])$', replacement='\\1') 20 | output$tableName <- renderText(paste0('Table t1', orgType)) 21 | 22 | conn <- dbConnect(MariaDB(), host=DB_HOST, dbname='demo1', user='root') 23 | tt <- dbReadTable(conn, paste0('t1', orgType)) 24 | output$tt <- renderTable(tt) 25 | dbDisconnect(conn) 26 | 27 | } 28 | 29 | shinyApp(ui, server) 30 | -------------------------------------------------------------------------------- /shiny-app/shiny/db-access/app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(tidyverse) 3 | library(RMariaDB) 4 | 5 | DB_HOST = 'mariadb' 6 | 7 | ui <- fluidPage( 8 | h3('Table T1A: '), tableOutput('t1A'), 9 | h3('Table T1B: '), tableOutput('t1B') 10 | ) 11 | 12 | server <- function(input, output, session) { 13 | 14 | conn <- dbConnect(MariaDB(), host=DB_HOST, dbname='demo1', user='root') 15 | t1A <- dbReadTable(conn, 't1A') 16 | output$t1A <- renderTable(t1A) 17 | t1B <- dbReadTable(conn, 't1B') 18 | output$t1B <- renderTable(t1B) 19 | dbDisconnect(conn) 20 | 21 | } 22 | 23 | shinyApp(ui, server) 24 | -------------------------------------------------------------------------------- /shiny-app/shiny/example-assertion.xml: -------------------------------------------------------------------------------- 1 | 2 | https://idp.localhost.localdomain/idp/shibboleth 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | mXk9dM5roVQgz/OKhGzgHYqkazTuUYw1yJAq6FCBBGs= 16 | 17 | 18 | 19 | gYFzbzPlxfBoMKNobo9l5e+EuwULrdpkTbxi+isnsrnOi9gUE/biDx1VUWs/66mL1p21iv0LLqC/ 20 | MtUhD+SV5JTTLKPMx0ZEIJRhg4iTlhbogbofdN0JFzpy2I8PmUzpS58Xp3blxUK4SgdNSi6caxla 21 | rQ58u0eOHM7HG8XZ0TJFU0gSfJ+v05oUYkrJCt88kKoYjKCUD2Jw4a1wy/9gOQmU3++lv0ShoAKB 22 | u2xMAsEMvQFR7WQDjPnpdxcZ74ECiSZnHIGgUO/9JWzRQcT8UdYRpbg4knPfkEnsgUBA2TGILina 23 | 4YWdrPdhPN3hdUBneheNV0DqVy9tqRwvyPocLw== 24 | 25 | 26 | 27 | MIIDkjCCAnoCCQCYAsXeiFCDcDANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMCVVMxCzAJBgNV 28 | BAgMAldBMRAwDgYDVQQHDAdPbHltcGlhMRswGQYDVQQKDBJDYXNjYWRpYSBBbmFseXRpY3MxHjAc 29 | BgNVBAMMFWxvY2FsaG9zdC5sb2NhbGRvbWFpbjEfMB0GCSqGSIb3DQEJARYQZG9ja2VyQGxvY2Fs 30 | aG9zdDAeFw0xODA1MTgxNzA4MjdaFw0zODA1MTMxNzA4MjdaMIGKMQswCQYDVQQGEwJVUzELMAkG 31 | A1UECAwCV0ExEDAOBgNVBAcMB09seW1waWExGzAZBgNVBAoMEkNhc2NhZGlhIEFuYWx5dGljczEe 32 | MBwGA1UEAwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMR8wHQYJKoZIhvcNAQkBFhBkb2NrZXJAbG9j 33 | YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoiIhucGDxgBPI7bjn9ze/jh0 34 | eT8An4BmHObw/xjq5REcx0/hq8A9oDmUQacsjP0+KWACrxc9JHdcL+TgZJGcrhkUdAhGkeEvgywP 35 | +UJh/BTAfBMMvHkWGxM0cZjpjfdzxEbnv/qanw8KKjlaOo7rf3ia8nUDfKgYGx+PlPylUvlvI1C0 36 | hkHbmlaxsdvCLIRQRYhZcWyRb2b9+UXJ2zuGZJUXXjvbXGZ8Loftlzjv64WiM5RPytzL1pVoc0OW 37 | pWvt1hLI5VeG7GiPYhjf1kVxFSjv0S1w6lldBAkCoPQcSTrfHnVO3MvN0MdR69UWfgHmq1A75ovx 38 | IQaGd3p5jBtXNwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBZgIlOr/utsLJ0WT6uVBTXyWlUYi3y 39 | hKkLk7B0QRuVycYG5KNYs9hiVkFDpCkiOeR7hhgUIZVSe8VNHF9l3zJdLQ0gXAe6fgkNhxdo9fB9 40 | /jYo5gu6H+p6b0T/9OrrrUKEHvBhYR7inus7/eLN3s9aWhzp8uAaBZ0UVCat944inzWMnT1nQhw3 41 | LVwfizJGcTKAdB8T50OKQhvoY/Xtc7RBa8bSu/q9nZ2xvdDgvJsssaqkeaRDgo7tpgs71DU4LyS1 42 | ph9O+lhsAgt8KwTji7X9VFAIUuWbuQfJl2ZQ6uyW6pOcTquPiAR7OX2Fc+ZrfAYDdDiCwpf80Inp 43 | OfwsJYfW 44 | 45 | 46 | 47 | 48 | AAdzZWNyZXQxUbVBrFjF8vpFsOsIXdsVCS399oa9SPzgF9maRyC+cp0+AFND90G3Nf5d0jWdAMQyyPmQ9vGBlmXe49kC+873omg99pytUo15/PTsC9JnOfu9ws/eDDh5CSS+7Rk0PumpV8kUdXKcJN4vFXBAo2Py 49 | 50 | 51 | 52 | 53 | 54 | 55 | https://sp.localhost.localdomain/shibboleth 56 | 57 | 58 | 59 | 60 | 61 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 62 | 63 | 64 | 65 | 66 | demouser1@localhost 67 | 68 | 69 | Demo1 70 | 71 | 72 | User 73 | 74 | 75 | Organization A 76 | 77 | 78 | LOCALDOMAIN:IDP:USER:demouser1 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /shiny-app/shiny/hostinfo/app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(tidyverse) 3 | 4 | ui <- fluidPage( 5 | h5('Server Info: '), verbatimTextOutput("info") 6 | ) 7 | 8 | server <- function(input, output, session) { 9 | 10 | hostname <- Sys.info()['nodename'] 11 | ip <- 'Unknown' 12 | 13 | os <- Sys.info()['sysname'] 14 | 15 | interface <- 'eth0' 16 | command <- '/sbin/ifconfig' 17 | 18 | if (os == 'Darwin') { 19 | interface <- 'en0' 20 | command <- 'ifconfig' 21 | } 22 | 23 | ifconfigOutput <- trimws(system(paste0(command, ' ', interface), intern=TRUE)) 24 | s <- ifconfigOutput[grepl(x=ifconfigOutput, pattern='^inet ')] 25 | ip <- gsub(x=s, pattern='inet [^0-9]*((?:[0-9]{1,3}\\.){3}(?:[0-9]{1,3})).+', replacement='\\1', perl=TRUE) 26 | 27 | output$info <- renderText({ 28 | paste0('Hostname: ', hostname, ", IP address: ", ip) 29 | }) 30 | 31 | } 32 | 33 | shinyApp(ui, server) 34 | -------------------------------------------------------------------------------- /shiny-app/shiny/saml/app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(xml2) 3 | library(lubridate) 4 | library(tidyverse) 5 | 6 | parseAssertion <- function(assertionUrl) { 7 | 8 | # ignoring SSL errors is ok. In a Docker context, there is no way to get a spoofed url 9 | a <- read_xml(httr::GET(assertionUrl, config = httr::config(ssl_verifyhost = FALSE, ssl_verifypeer=FALSE))) 10 | 11 | ret <- list() 12 | 13 | ret$IssuedDateTime <- a %>% xml_find_first('/saml2:Assertion/@IssueInstant') %>% xml_text() %>% as_datetime() 14 | ret$Issuer <- a %>% xml_find_first('/saml2:Assertion/saml2:Issuer') %>% xml_text() 15 | ret$ExpirationDateTime <- a %>% xml_find_first('/saml2:Assertion/saml2:Conditions/@NotOnOrAfter') %>% xml_text() %>% as_datetime() 16 | ret$AuthenticationDateTime <- a %>% xml_find_first('/saml2:Assertion/saml2:AuthnStatement/@AuthnInstant') %>% xml_text() %>% as_datetime() 17 | ret$AuthenticationContextClass <- a %>% xml_find_first('/saml2:Assertion/saml2:AuthnStatement/saml2:AuthnContext/saml2:AuthnContextClassRef') %>% xml_text() 18 | 19 | ret$Attributes <- map_df(xml_find_all(a, '//saml2:Attribute'), function(node) { 20 | tibble(Attribute=xml_attr(node, 'Name'), Value=xml_text(xml_find_first(node, 'saml2:AttributeValue'))) 21 | }) 22 | 23 | ret 24 | 25 | } 26 | 27 | ui <- fluidPage( 28 | h5('Server Info: '), verbatimTextOutput("info"), 29 | # h5('Shib url: '), verbatimTextOutput("shib"), 30 | h5('SAML Authentication Information: '), uiOutput('bList'), 31 | h5('Assertion Attributes:'), tableOutput('assertionAttributes') 32 | ) 33 | 34 | server <- function(input, output, session) { 35 | 36 | hostname <- Sys.info()['nodename'] 37 | ip <- 'Unknown' 38 | 39 | os <- Sys.info()['sysname'] 40 | 41 | interface <- 'eth0' 42 | command <- '/sbin/ifconfig' 43 | 44 | if (os == 'Darwin') { 45 | interface <- 'en0' 46 | command <- 'ifconfig' 47 | } 48 | 49 | ifconfigOutput <- trimws(system(paste0(command, ' ', interface), intern=TRUE)) 50 | s <- ifconfigOutput[grepl(x=ifconfigOutput, pattern='^inet ')] 51 | ip <- gsub(x=s, pattern='inet [^0-9]*((?:[0-9]{1,3}\\.){3}(?:[0-9]{1,3})).+', replacement='\\1', perl=TRUE) 52 | 53 | output$info <- renderText({ 54 | paste0('Hostname: ', hostname, ", IP address: ", ip) 55 | }) 56 | 57 | #output$shib <- renderText({ 58 | # session$request$HTTP_SHIB_ASSERTION_01 59 | #}) 60 | 61 | assertion <- session$request$HTTP_SHIB_ASSERTION_01 62 | 63 | if (is.null(assertion)) { 64 | 65 | output$bList <- renderUI({tags$p(tags$span('No authentication info: shiny is not running in a SAML context.', style='font-family: italic'))}) 66 | output$assertionAttributes <- renderUI({tags$p(tags$span('No assertion attributes: shiny is not running in a SAML context.', style='font-family: italic'))}) 67 | 68 | } else { 69 | 70 | assertionList <- parseAssertion(assertion) 71 | 72 | output$bList <- renderUI({ 73 | tags$ul( 74 | tags$li(paste0('Assertion Issued At: ', assertionList$IssuedDateTime)), 75 | tags$li(paste0('Assertion Issued By: ', assertionList$Issuer)), 76 | tags$li(paste0('Assertion Expires At: ', assertionList$ExpirationDateTime)), 77 | tags$li(paste0('Authentication Occurred At: ', assertionList$AuthenticationDateTime)), 78 | tags$li(paste0('Authentication Class: ', assertionList$AuthenticationContextClass)) 79 | ) 80 | }) 81 | 82 | output$assertionAttributes <- renderTable(assertionList$Attributes) 83 | 84 | } 85 | 86 | } 87 | 88 | shinyApp(ui, server) 89 | -------------------------------------------------------------------------------- /shiny-app/shiny/shiny.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | --------------------------------------------------------------------------------