├── .gitignore ├── LICENSE.md ├── Makefile ├── README.md ├── pom.xml └── src └── main ├── java └── gov │ └── gsa │ └── samplesp │ └── App.java └── resources ├── application.properties ├── static ├── basscss.min.css ├── login-gov.svg ├── seal.png └── usa-flag.png └── templates ├── error.html ├── index.html ├── logout.html ├── success.html └── success_view.html /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.idea 3 | samplesp.iml 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | As a work of the United States Government, this project is in the 2 | public domain within the United States. 3 | 4 | Additionally, we waive copyright and related rights in the work 5 | worldwide through the CC0 1.0 Universal public domain dedication. 6 | 7 | ## CC0 1.0 Universal Summary 8 | 9 | This is a human-readable summary of the [Legal Code (read the full text)](https://creativecommons.org/publicdomain/zero/1.0/legalcode). 10 | 11 | ### No Copyright 12 | 13 | The person who associated a work with this deed has dedicated the work to 14 | the public domain by waiving all of his or her rights to the work worldwide 15 | under copyright law, including all related and neighboring rights, to the 16 | extent allowed by law. 17 | 18 | You can copy, modify, distribute and perform the work, even for commercial 19 | purposes, all without asking permission. 20 | 21 | ### Other Information 22 | 23 | In no way are the patent or trademark rights of any person affected by CC0, 24 | nor are the rights that other persons may have in the work or in how the 25 | work is used, such as publicity or privacy rights. 26 | 27 | Unless expressly stated otherwise, the person who associated a work with 28 | this deed makes no warranties about the work, and disclaims liability for 29 | all uses of the work, to the fullest extent permitted by applicable law. 30 | When using or citing the work, you should not imply endorsement by the 31 | author or the affirmer. 32 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for building and running the project. 2 | # The purpose of this Makefile is to avoid developers having to remember 3 | # project-specific commands for building, running, etc. Recipes longer 4 | # than one or two lines should live in script files of their own in the 5 | # bin/ directory. 6 | 7 | all: build 8 | 9 | build: 10 | mvn compile install 11 | 12 | run: build 13 | mvn spring-boot:run 14 | 15 | test: 16 | mvm test 17 | 18 | .PHONY: build run test 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This sample SP has been retired. It was used for early prototyping for integrations with login.gov and has not been maintained. It has confirmed vulnerabilities and should not be used for production itegrations. 2 | 3 | For maintained examples of integrations with login.gov please refer to: 4 | 5 | - https://github.com/18F/identity-saml-sinatra 6 | - https://github.com/18F/identity-oidc-sinatra 7 | 8 | # Warning: 9 | 10 | This sample SP has been retired. It was used for early prototyping for integrations with login.gov and has not been maintained. It has confirmed vulnerabilities and should not be used for production itegrations. 11 | 12 | For maintained examples of SAML integrations with login.gov please refer to: 13 | 14 | - https://github.com/18F/identity-saml-rails 15 | - https://github.com/18F/identity-saml-sinatra 16 | 17 | # Login.gov Sample SP — Java / Spring 18 | 19 | An example service provider (SP) written in Java integrated with [Login.gov](https://login.gov). This simple web app is based on [Spring Boot](https://projects.spring.io/spring-boot/) and [OneLogin's SAML Java Toolkit](https://github.com/onelogin/java-saml), which supports SAML-based SSO and SLO. 20 | 21 | ## Prerequisites 22 | 23 | - JDK 8+ 24 | - Apache Maven 25 | 26 | On macOS, install Java and Maven using Homebrew: 27 | 28 | ```bash 29 | brew tap caskroom/cask 30 | brew cask install java 31 | brew install maven 32 | ``` 33 | 34 | ## Build and run 35 | 36 | ```bash 37 | mvn compile 38 | mvn spring-boot:run 39 | ``` 40 | 41 | View at `http://localhost:4567` 42 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | gov.gsa 5 | samplesp 6 | jar 7 | 1.0-SNAPSHOT 8 | SampleSP 9 | https://github.com/18F/identity-idp/ 10 | 11 | 12 | 1.8 13 | UTF-8 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter-parent 19 | 1.3.6.RELEASE 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-thymeleaf 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-devtools 30 | true 31 | 32 | 33 | junit 34 | junit 35 | 3.8.1 36 | test 37 | 38 | 39 | org.springframework.security.extensions 40 | spring-security-saml2-core 41 | 1.0.2.RELEASE 42 | 43 | 44 | xml-apis 45 | xml-apis 46 | 1.4.01 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | org.apache.maven.plugins 58 | maven-compiler-plugin 59 | 60 | javac-with-errorprone 61 | true 62 | 8 63 | 8 64 | 8 65 | 8 66 | 67 | -Xlint:unchecked 68 | 69 | 70 | 71 | 72 | org.codehaus.plexus 73 | plexus-compiler-javac-errorprone 74 | 2.5 75 | 76 | 78 | 79 | com.google.errorprone 80 | error_prone_core 81 | 2.0.9 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/main/java/gov/gsa/samplesp/App.java: -------------------------------------------------------------------------------- 1 | package gov.gsa.samplesp; 2 | 3 | import javax.xml.parsers.DocumentBuilderFactory; 4 | import javax.xml.parsers.DocumentBuilder; 5 | 6 | import java.io.IOException; 7 | import java.lang.System; 8 | import java.util.List; 9 | import java.util.ArrayList; 10 | import java.util.stream.IntStream; 11 | import javax.servlet.http.Cookie; 12 | import javax.servlet.http.HttpServletResponse; 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.xml.namespace.QName; 15 | import org.opensaml.Configuration; 16 | import org.opensaml.DefaultBootstrap; 17 | import org.opensaml.common.SAMLObject; 18 | import org.opensaml.common.SAMLObjectBuilder; 19 | import org.opensaml.common.SAMLVersion; 20 | import org.opensaml.common.binding.SAMLMessageContext; 21 | import org.opensaml.common.binding.BasicSAMLMessageContext; 22 | import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder; 23 | import org.opensaml.saml2.binding.decoding.HTTPPostDecoder; 24 | import org.opensaml.saml2.core.AuthnContext; 25 | import org.opensaml.saml2.core.Response; 26 | import org.opensaml.saml2.core.Assertion; 27 | import org.opensaml.saml2.core.EncryptedAssertion; 28 | import org.opensaml.saml2.core.StatusCode; 29 | import org.opensaml.saml2.core.AuthnContextClassRef; 30 | import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; 31 | import org.opensaml.saml2.core.AuthnRequest; 32 | import org.opensaml.saml2.core.Issuer; 33 | import org.opensaml.saml2.core.RequestedAuthnContext; 34 | import org.opensaml.saml2.encryption.Decrypter; 35 | import org.opensaml.saml2.metadata.Endpoint; 36 | import org.opensaml.saml2.metadata.SingleSignOnService; 37 | import org.opensaml.ws.message.encoder.MessageEncodingException; 38 | import org.opensaml.ws.message.decoder.MessageDecodingException; 39 | import org.opensaml.ws.transport.http.HttpServletResponseAdapter; 40 | import org.opensaml.ws.transport.http.HttpServletRequestAdapter; 41 | import org.opensaml.xml.ConfigurationException; 42 | import org.opensaml.xml.XMLObjectBuilder; 43 | import org.opensaml.xml.XMLObjectBuilderFactory; 44 | import org.opensaml.xml.XMLObject; 45 | import org.opensaml.xml.io.UnmarshallerFactory; 46 | import org.opensaml.xml.io.Unmarshaller; 47 | import org.opensaml.xml.util.Base64; 48 | import org.opensaml.xml.security.SecurityException; 49 | import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; 50 | import org.opensaml.xml.security.keyinfo.StaticKeyInfoCredentialResolver; 51 | import org.opensaml.xml.security.credential.Credential; 52 | import org.opensaml.xml.encryption.DecryptionException; 53 | import org.opensaml.xml.signature.X509Certificate; 54 | import org.springframework.boot.SpringApplication; 55 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 56 | import org.springframework.stereotype.Controller; 57 | import org.springframework.ui.Model; 58 | import org.springframework.web.bind.annotation.CookieValue; 59 | import org.springframework.web.bind.annotation.RequestMapping; 60 | import org.springframework.web.bind.annotation.RequestMethod; 61 | import org.springframework.web.bind.annotation.RequestParam; 62 | import org.springframework.web.bind.annotation.RestController; 63 | 64 | @Controller 65 | @EnableAutoConfiguration 66 | public class App { 67 | 68 | public static void main(String[] args) { 69 | try { 70 | DefaultBootstrap.bootstrap(); 71 | } catch (ConfigurationException e) { 72 | System.err.println("DefaultBootstrap.bootstrap failed"); 73 | return; 74 | } 75 | SpringApplication.run(App.class, args); 76 | } 77 | 78 | private XMLObjectBuilder getBuilder(QName name) { 79 | return Configuration.getBuilderFactory().getBuilder(name); 80 | } 81 | 82 | private Issuer buildIssuer() { 83 | @SuppressWarnings("unchecked") 84 | SAMLObjectBuilder issuerBuilder = (SAMLObjectBuilder) getBuilder(Issuer.DEFAULT_ELEMENT_NAME); 85 | Issuer issuer = issuerBuilder.buildObject(); 86 | issuer.setValue("urn:gov:gsa:SAML:2.0.profiles:sp:sso:localhost"); 87 | return issuer; 88 | 89 | } 90 | 91 | private AuthnRequest buildAuthnRequest() { 92 | @SuppressWarnings("unchecked") 93 | SAMLObjectBuilder authn_builder = (SAMLObjectBuilder) getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME); 94 | AuthnRequest req = authn_builder.buildObject(); 95 | req.setIsPassive(true); 96 | req.setVersion(SAMLVersion.VERSION_20); 97 | req.setAssertionConsumerServiceURL("http://localhost:4567/consume"); 98 | req.setProtocolBinding("HTTP_POST"); 99 | req.setRequestedAuthnContext(buildAuthnContext()); 100 | req.setIssuer(buildIssuer()); 101 | 102 | return req; 103 | } 104 | 105 | private RequestedAuthnContext buildAuthnContext() { 106 | @SuppressWarnings("unchecked") 107 | SAMLObjectBuilder contextRefBuilder = (SAMLObjectBuilder) getBuilder(AuthnContextClassRef.DEFAULT_ELEMENT_NAME); 108 | AuthnContextClassRef classRef = contextRefBuilder.buildObject(); 109 | classRef.setAuthnContextClassRef("http://idmanagement.gov/ns/assurance/loa/1"); 110 | 111 | @SuppressWarnings("unchecked") 112 | SAMLObjectBuilder builder = (SAMLObjectBuilder) getBuilder(RequestedAuthnContext.DEFAULT_ELEMENT_NAME); 113 | RequestedAuthnContext authnContext = builder.buildObject(); 114 | authnContext.setComparison(AuthnContextComparisonTypeEnumeration.EXACT); 115 | authnContext.getAuthnContextClassRefs().add(classRef); 116 | return authnContext; 117 | } 118 | 119 | private Endpoint getIDPEndpoint() { 120 | @SuppressWarnings("unchecked") 121 | SAMLObjectBuilder builder = (SAMLObjectBuilder) getBuilder(SingleSignOnService.DEFAULT_ELEMENT_NAME); 122 | Endpoint samlEndpoint = builder.buildObject(); 123 | samlEndpoint.setLocation("http://localhost:3000/api/saml/auth"); 124 | samlEndpoint.setResponseLocation("http://bar.com"); 125 | return samlEndpoint; 126 | } 127 | 128 | private Endpoint getIDPLogoutEndpoint() { 129 | @SuppressWarnings("unchecked") 130 | SAMLObjectBuilder builder = (SAMLObjectBuilder) getBuilder(SingleSignOnService.DEFAULT_ELEMENT_NAME); 131 | Endpoint samlEndpoint = builder.buildObject(); 132 | samlEndpoint.setLocation("http://localhost:3000/api/saml/logout"); 133 | samlEndpoint.setResponseLocation("http://bar.com"); 134 | return samlEndpoint; 135 | } 136 | 137 | @RequestMapping("/login") 138 | String login(HttpServletResponse response) throws IOException, MessageEncodingException { 139 | AuthnRequest req = buildAuthnRequest(); 140 | 141 | BasicSAMLMessageContext context = new BasicSAMLMessageContext(); 142 | HttpServletResponseAdapter transport = new HttpServletResponseAdapter(response, false); 143 | context.setOutboundMessageTransport(transport); 144 | context.setPeerEntityEndpoint(getIDPEndpoint()); 145 | context.setOutboundSAMLMessage(req); 146 | 147 | System.out.println("req = " + req); 148 | HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); 149 | encoder.encode(context); 150 | System.out.println("location = " + response.getHeader("location")); 151 | return null; 152 | } 153 | 154 | @RequestMapping("/logout") 155 | String logout(HttpServletResponse response) throws IOException, MessageEncodingException { 156 | // AuthnRequest req = buildAuthnRequest(); 157 | 158 | // BasicSAMLMessageContext context = new BasicSAMLMessageContext(); 159 | // HttpServletResponseAdapter transport = new HttpServletResponseAdapter(response, false); 160 | // context.setOutboundMessageTransport(transport); 161 | // context.setPeerEntityEndpoint(getIDPLogoutEndpoint()); 162 | // context.setOutboundSAMLMessage(req); 163 | 164 | // System.out.println("req = " + req); 165 | // HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); 166 | // encoder.encode(context); 167 | // System.out.println("location = " + response.getHeader("location")); 168 | return "logout"; 169 | } 170 | 171 | 172 | private SAMLMessageContext extractSAMLMessageContext(HttpServletRequest request) throws MessageDecodingException, SecurityException { 173 | BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); 174 | 175 | messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(request)); 176 | //messageContext.setSecurityPolicyResolver(resolver); 177 | 178 | HTTPPostDecoder decoder = new HTTPPostDecoder(); 179 | decoder.decode(messageContext); 180 | return messageContext; 181 | } 182 | 183 | @RequestMapping(value="/consume", method=RequestMethod.POST) 184 | String consume(HttpServletRequest request, HttpServletResponse response, 185 | @RequestParam(value="SAMLResponse", required=true) String samlResponseString) throws MessageDecodingException, SecurityException { 186 | System.out.println("SAMLResponseString!!!! " + samlResponseString.length()); 187 | SAMLMessageContext messageContext = extractSAMLMessageContext(request); 188 | 189 | Response samlResponse = (Response) messageContext.getInboundSAMLMessage(); 190 | String statusCode = samlResponse.getStatus().getStatusCode().getValue(); 191 | if (!StatusCode.SUCCESS_URI.equals(statusCode)) { 192 | System.out.println("SAML Logon failed: " + statusCode); 193 | return "redirect:/failure"; 194 | } 195 | 196 | List assertionList = samlResponse.getAssertions(); 197 | 198 | // Decrypt assertions 199 | if (samlResponse.getEncryptedAssertions().size() > 0) { 200 | // Credential encryptionCredential = new X509CredentialImpl(ssoAgentConfig.getSAML2().getSSOAgentX509Credential()); 201 | Credential encryptionCredential = null; 202 | KeyInfoCredentialResolver resolver = new StaticKeyInfoCredentialResolver(encryptionCredential); 203 | Decrypter decrypter = new Decrypter(null, resolver, null); 204 | decrypter.setRootInNewDocument(true); 205 | 206 | assertionList = new ArrayList(samlResponse.getAssertions().size() + samlResponse.getEncryptedAssertions().size()); 207 | assertionList.addAll(samlResponse.getAssertions()); 208 | List encryptedAssertionList = samlResponse.getEncryptedAssertions(); 209 | for (EncryptedAssertion ea : encryptedAssertionList) { 210 | try { 211 | System.out.println("Decrypting assertion"); 212 | 213 | Assertion decryptedAssertion = decrypter.decrypt(ea); 214 | assertionList.add(decryptedAssertion); 215 | } catch (DecryptionException e) { 216 | System.out.println("Decryption of received assertion failed, assertion will be skipped"); 217 | } 218 | } 219 | } 220 | 221 | for (Assertion assertion : assertionList) { 222 | System.out.println("AssertionList"); 223 | System.out.println("assertion: " + assertion); 224 | } 225 | String email = "goobar"; 226 | response.addCookie(new Cookie("email", email)); 227 | return "redirect:/success"; 228 | } 229 | 230 | @RequestMapping("/success") 231 | String success(Model model, 232 | @CookieValue(value="email") String email_cookie) { 233 | model.addAttribute("email", email_cookie); 234 | return "success"; 235 | } 236 | 237 | @RequestMapping("/") 238 | String root(Model model) { 239 | model.addAttribute("intstream", IntStream.range(0, 6).iterator()); 240 | return "index"; 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port = 4567 2 | security.basic.enabled = false 3 | -------------------------------------------------------------------------------- /src/main/resources/static/basscss.min.css: -------------------------------------------------------------------------------- 1 | /*! Basscss | http://basscss.com | MIT License */body{margin:0}img{max-width:100%}svg{max-height:100%}fieldset,input,select,textarea{font-family:inherit;font-size:1rem;box-sizing:border-box;margin-top:0;margin-bottom:0}label{vertical-align:middle}input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{height:2.25rem;padding:.5rem;vertical-align:middle;-webkit-appearance:none}select{line-height:1.75;padding:.5rem}select:not([multiple]){height:2.25rem;vertical-align:middle}textarea{line-height:1.75;padding:.5rem}table{border-collapse:separate;border-spacing:0;max-width:100%;width:100%}th{text-align:left;font-weight:700}td,th{padding:.25rem 1rem;line-height:inherit}th{vertical-align:bottom}td{vertical-align:top}body{line-height:1.5;font-size:100%}body,h1,h2,h3,h4,h5,h6{font-family:Helvetica Neue,Helvetica,sans-serif}h1,h2,h3,h4,h5,h6{font-weight:700;line-height:1.25;margin-top:1em;margin-bottom:.5em}dl,ol,p,ul{margin-top:0;margin-bottom:1rem}code,pre,samp{font-family:Source Code Pro,Consolas,monospace;font-size:inherit}pre{margin-top:0;margin-bottom:1rem;overflow-x:scroll}h1{font-size:2rem}h2{font-size:1.5rem}h3{font-size:1.25rem}h4{font-size:1rem}h5{font-size:.875rem}h6{font-size:.75rem}body{color:#111;background-color:#fff}a{color:#0074d9;text-decoration:none}a:hover{text-decoration:underline}code,pre{background-color:transparent;border-radius:3px}hr{border:0;border-bottom-style:solid;border-bottom-width:1px;border-bottom-color:rgba(0,0,0,.125)}.field{border:1px solid rgba(0,0,0,.125);border-radius:3px}.field.is-focused,.field:focus{outline:none;border-color:#0074d9;box-shadow:0 0 0 2px rgba(0,116,217,.5)}.field.is-disabled,.field:disabled{background-color:rgba(0,0,0,.125);opacity:.5}.field.is-read-only,.field:-moz-read-only:not(select){background-color:rgba(0,0,0,.125)}.field.is-read-only,.field:read-only:not(select){background-color:rgba(0,0,0,.125)}.field.is-success{border-color:#2ecc40}.field.is-success.is-focused,.field.is-success:focus{box-shadow:0 0 0 2px rgba(46,204,64,.5)}.field.is-warning{border-color:#ffdc00}.field.is-warning.is-focused,.field.is-warning:focus{box-shadow:0 0 0 2px rgba(255,220,0,.5)}.field.is-error,.field:invalid{border-color:#ff4136}.field.is-error.is-focused,.field.is-error:focus,.field:invalid.is-focused,.field:invalid:focus{box-shadow:0 0 0 2px rgba(255,65,54,.5)}.table-light td,.table-light th{border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgba(0,0,0,.125)}.table-light tr:last-child td{border-bottom:0}.btn{font-family:inherit;font-size:inherit;font-weight:700;cursor:pointer;display:inline-block;line-height:1.125rem;padding:.5rem 1rem;margin:0;height:auto;border:1px solid transparent;vertical-align:middle;-webkit-appearance:none;color:inherit;background-color:transparent}.btn,.btn:hover{text-decoration:none}.btn:focus{outline:none;border-color:rgba(0,0,0,.125);box-shadow:0 0 0 3px rgba(0,0,0,.25)}::-moz-focus-inner{border:0;padding:0}.btn-primary{color:#fff;background-color:#0074d9;border-radius:3px}.btn-primary:hover{box-shadow:inset 0 0 0 20rem rgba(0,0,0,.0625)}.btn-primary:active{box-shadow:inset 0 0 0 20rem rgba(0,0,0,.125),inset 0 3px 4px 0 rgba(0,0,0,.25),0 0 1px rgba(0,0,0,.125)}.btn-primary.is-disabled,.btn-primary:disabled{opacity:.5}.btn-outline,.btn-outline:hover{border-color:currentcolor}.btn-outline{border-radius:3px}.btn-outline:hover{box-shadow:inset 0 0 0 20rem rgba(0,0,0,.0625)}.btn-outline:active{box-shadow:inset 0 0 0 20rem rgba(0,0,0,.125),inset 0 3px 4px 0 rgba(0,0,0,.25),0 0 1px rgba(0,0,0,.125)}.btn-outline.is-disabled,.btn-outline:disabled{opacity:.5}.h1{font-size:2rem}.h2{font-size:1.5rem}.h3{font-size:1.25rem}.h4{font-size:1rem}.h5{font-size:.875rem}.h6{font-size:.75rem}.font-family-inherit{font-family:inherit}.font-size-inherit{font-size:inherit}.text-decoration-none{text-decoration:none}.bold{font-weight:700}.regular{font-weight:400}.italic{font-style:italic}.caps{text-transform:uppercase;letter-spacing:.2em}.left-align{text-align:left}.center{text-align:center}.right-align{text-align:right}.justify{text-align:justify}.nowrap{white-space:nowrap}.break-word{word-wrap:break-word}.line-height-1{line-height:1}.line-height-2{line-height:1.125}.line-height-3{line-height:1.25}.line-height-4{line-height:1.5}.list-style-none{list-style:none}.underline{text-decoration:underline}.truncate{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.list-reset{list-style:none;padding-left:0}.inline{display:inline}.block{display:block}.inline-block{display:inline-block}.table{display:table}.table-cell{display:table-cell}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-auto{overflow:auto}.clearfix:after,.clearfix:before{content:" ";display:table}.clearfix:after{clear:both}.left{float:left}.right{float:right}.fit{max-width:100%}.border-box{box-sizing:border-box}.align-baseline{vertical-align:baseline}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.align-bottom{vertical-align:bottom}.m0{margin:0}.mt0{margin-top:0}.mr0{margin-right:0}.mb0{margin-bottom:0}.ml0{margin-left:0}.m1{margin:.5rem}.mt1{margin-top:.5rem}.mr1{margin-right:.5rem}.mb1{margin-bottom:.5rem}.ml1{margin-left:.5rem}.m2{margin:1rem}.mt2{margin-top:1rem}.mr2{margin-right:1rem}.mb2{margin-bottom:1rem}.ml2{margin-left:1rem}.m3{margin:2rem}.mt3{margin-top:2rem}.mr3{margin-right:2rem}.mb3{margin-bottom:2rem}.ml3{margin-left:2rem}.m4{margin:4rem}.mt4{margin-top:4rem}.mr4{margin-right:4rem}.mb4{margin-bottom:4rem}.ml4{margin-left:4rem}.mxn1{margin-left:-.5rem;margin-right:-.5rem}.mxn2{margin-left:-1rem;margin-right:-1rem}.mxn3{margin-left:-2rem;margin-right:-2rem}.mxn4{margin-left:-4rem;margin-right:-4rem}.mx-auto{margin-left:auto;margin-right:auto}.p0{padding:0}.p1{padding:.5rem}.py1{padding-top:.5rem;padding-bottom:.5rem}.px1{padding-left:.5rem;padding-right:.5rem}.p2{padding:1rem}.py2{padding-top:1rem;padding-bottom:1rem}.px2{padding-left:1rem;padding-right:1rem}.p3{padding:2rem}.py3{padding-top:2rem;padding-bottom:2rem}.px3{padding-left:2rem;padding-right:2rem}.p4{padding:4rem}.py4{padding-top:4rem;padding-bottom:4rem}.px4{padding-left:4rem;padding-right:4rem}.relative{position:relative}.absolute{position:absolute}.fixed{position:fixed}.top-0{top:0}.right-0{right:0}.bottom-0{bottom:0}.left-0{left:0}.z1{z-index:1}.z2{z-index:2}.z3{z-index:3}.z4{z-index:4}.lg-show,.md-show,.sm-show{display:none!important}@media (min-width:40em){.sm-show{display:block!important}}@media (min-width:52em){.md-show{display:block!important}}@media (min-width:64em){.lg-show{display:block!important}}@media (min-width:40em){.sm-hide{display:none!important}}@media (min-width:52em){.md-hide{display:none!important}}@media (min-width:64em){.lg-hide{display:none!important}}.display-none{display:none!important}.hide{position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.container{max-width:64em;margin-left:auto;margin-right:auto}.col{float:left}.col,.col-right{box-sizing:border-box}.col-right{float:right}.col-1{width:8.33333%}.col-2{width:16.66667%}.col-3{width:25%}.col-4{width:33.33333%}.col-5{width:41.66667%}.col-6{width:50%}.col-7{width:58.33333%}.col-8{width:66.66667%}.col-9{width:75%}.col-10{width:83.33333%}.col-11{width:91.66667%}.col-12{width:100%}@media (min-width:40em){.sm-col{float:left;box-sizing:border-box}.sm-col-right{float:right;box-sizing:border-box}.sm-col-1{width:8.33333%}.sm-col-2{width:16.66667%}.sm-col-3{width:25%}.sm-col-4{width:33.33333%}.sm-col-5{width:41.66667%}.sm-col-6{width:50%}.sm-col-7{width:58.33333%}.sm-col-8{width:66.66667%}.sm-col-9{width:75%}.sm-col-10{width:83.33333%}.sm-col-11{width:91.66667%}.sm-col-12{width:100%}}@media (min-width:52em){.md-col{float:left;box-sizing:border-box}.md-col-right{float:right;box-sizing:border-box}.md-col-1{width:8.33333%}.md-col-2{width:16.66667%}.md-col-3{width:25%}.md-col-4{width:33.33333%}.md-col-5{width:41.66667%}.md-col-6{width:50%}.md-col-7{width:58.33333%}.md-col-8{width:66.66667%}.md-col-9{width:75%}.md-col-10{width:83.33333%}.md-col-11{width:91.66667%}.md-col-12{width:100%}}@media (min-width:64em){.lg-col{float:left;box-sizing:border-box}.lg-col-right{float:right;box-sizing:border-box}.lg-col-1{width:8.33333%}.lg-col-2{width:16.66667%}.lg-col-3{width:25%}.lg-col-4{width:33.33333%}.lg-col-5{width:41.66667%}.lg-col-6{width:50%}.lg-col-7{width:58.33333%}.lg-col-8{width:66.66667%}.lg-col-9{width:75%}.lg-col-10{width:83.33333%}.lg-col-11{width:91.66667%}.lg-col-12{width:100%}}.flex{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.flex-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.flex-wrap{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-center{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.flex-baseline{-webkit-box-align:baseline;-webkit-align-items:baseline;-ms-flex-align:baseline;align-items:baseline}.flex-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch}.flex-start{-webkit-box-align:start;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start}.flex-end{-webkit-box-align:end;-webkit-align-items:flex-end;-ms-flex-align:end;align-items:flex-end}.flex-justify{-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.flex-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;-ms-flex:1 1 auto;flex:1 1 auto;min-width:0;min-height:0}.flex-grow{-webkit-box-flex:1;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto}.flex-none{-webkit-box-flex:0;-webkit-flex:none;-ms-flex:none;flex:none}.flex-first{-webkit-box-ordinal-group:0;-webkit-order:-1;-ms-flex-order:-1;order:-1}.flex-last{-webkit-box-ordinal-group:100000;-webkit-order:99999;-ms-flex-order:99999;order:99999}@media (min-width:40em){.sm-flex{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}}@media (min-width:52em){.md-flex{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}}@media (min-width:64em){.lg-flex{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}}.border{border:1px solid rgba(0,0,0,.125)}.border-top{border-top-style:solid;border-top-width:1px;border-top-color:rgba(0,0,0,.125)}.border-right{border-right-style:solid;border-right-width:1px;border-right-color:rgba(0,0,0,.125)}.border-bottom{border-bottom-style:solid;border-bottom-width:1px;border-bottom-color:rgba(0,0,0,.125)}.border-left{border-left-style:solid;border-left-width:1px;border-left-color:rgba(0,0,0,.125)}.border-none{border:0}.rounded{border-radius:3px}.circle{border-radius:50%}.rounded-top{border-radius:3px 3px 0 0}.rounded-right{border-radius:0 3px 3px 0}.rounded-bottom{border-radius:0 0 3px 3px}.rounded-left{border-radius:3px 0 0 3px}.not-rounded{border-radius:0}.black{color:#111}.gray{color:#aaa}.silver{color:#ddd}.white{color:#fff}.aqua{color:#7fdbff}.blue{color:#0074d9}.navy{color:#001f3f}.teal{color:#39cccc}.green{color:#2ecc40}.olive{color:#3d9970}.lime{color:#01ff70}.yellow{color:#ffdc00}.orange{color:#ff851b}.red{color:#ff4136}.fuchsia{color:#f012be}.purple{color:#b10dc9}.maroon{color:#85144b}.color-inherit{color:inherit}.muted{opacity:.5}.bg-black{background-color:#111}.bg-gray{background-color:#aaa}.bg-silver{background-color:#ddd}.bg-white{background-color:#fff}.bg-aqua{background-color:#7fdbff}.bg-blue{background-color:#0074d9}.bg-navy{background-color:#001f3f}.bg-teal{background-color:#39cccc}.bg-green{background-color:#2ecc40}.bg-olive{background-color:#3d9970}.bg-lime{background-color:#01ff70}.bg-yellow{background-color:#ffdc00}.bg-orange{background-color:#ff851b}.bg-red{background-color:#ff4136}.bg-fuchsia{background-color:#f012be}.bg-purple{background-color:#b10dc9}.bg-maroon{background-color:#85144b}.bg-darken-1{background-color:rgba(0,0,0,.0625)}.bg-darken-2{background-color:rgba(0,0,0,.125)}.bg-darken-3{background-color:rgba(0,0,0,.25)}.bg-darken-4{background-color:rgba(0,0,0,.5)}.bg-lighten-1{background-color:hsla(0,0%,100%,.0625)}.bg-lighten-2{background-color:hsla(0,0%,100%,.125)}.bg-lighten-3{background-color:hsla(0,0%,100%,.25)}.bg-lighten-4{background-color:hsla(0,0%,100%,.5)} -------------------------------------------------------------------------------- /src/main/resources/static/login-gov.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | rgb 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/main/resources/static/seal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/identity-saml-java/b7e269492d5bb0981489820256fb9b385ea087a5/src/main/resources/static/seal.png -------------------------------------------------------------------------------- /src/main/resources/static/usa-flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/identity-saml-java/b7e269492d5bb0981489820256fb9b385ea087a5/src/main/resources/static/usa-flag.png -------------------------------------------------------------------------------- /src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Identity 4 | 5 | 6 | 7 | 8 |
9 | TEST SITE - Do not use real personal information (demo purposes only) - TEST SITE 10 |
11 |
12 | U.S. flag 13 | A DEMO website of the United States government 14 |
15 |
16 | 17 |
18 |
19 |
20 |

You need to login to view this page. Please log in to continue.

21 |
22 | 25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Identity 4 | 5 | 6 | 7 | 8 |
9 | TEST SITE - Do not use real personal information (demo purposes only) - TEST SITE 10 |
11 |
12 | U.S. flag 13 | A DEMO website of the United States government 14 |
15 |
16 | 17 |
18 |
19 |
20 |

Please log in to continue.

21 |
22 | 25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/resources/templates/logout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Identity 4 | 5 | 6 | 7 | 8 |
9 | TEST SITE - Do not use real personal information (demo purposes only) - TEST SITE 10 |
11 |
12 | U.S. flag 13 | A DEMO website of the United States government 14 |
15 |
16 | 17 |
18 |
19 |
20 |

You have been logged out. Please log in to continue.

21 |
22 | 25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/resources/templates/success.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Identity 4 | 5 | 6 | 7 | 8 |
9 | TEST SITE - Do not use real personal information (demo purposes only) - TEST SITE 10 |
11 |
12 | U.S. flag 13 | A DEMO website of the United States government 14 |
15 |
16 | 17 |
18 | 19 |
20 |
21 |
22 | Success! 23 | Your email is foo@bar.com. 24 |
Logout 25 |
26 |
27 |
28 | 29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/resources/templates/success_view.html: -------------------------------------------------------------------------------- 1 | 2 | SUCCESS TEMPLATIE 3 | 4 | --------------------------------------------------------------------------------