├── .github ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── release-drafter.yml └── workflows │ ├── cd.yaml │ ├── codeql.yml │ ├── dependency-review.yml │ └── jenkins-security-scan.yml ├── .gitignore ├── .mvn ├── extensions.xml └── maven.config ├── CHANGELOG.md ├── Jenkinsfile ├── LICENSE ├── NOTICE ├── README.md ├── doc ├── ADFS_CONFIG.md ├── CONFIGURE.md ├── CONFIGURE_AZURE.md ├── CONFIGURE_KEYCLOAK.md ├── TROUBLESHOOTING.md └── images │ ├── ADFS-claim-001.png │ ├── ADFS-claim-002.png │ ├── ADFS-claim-003.png │ ├── ADFS-wizard-001.png │ ├── ADFS-wizard-002.png │ ├── ADFS-wizard-003.png │ ├── ADFS-wizard-004.png │ ├── ADFS-wizard-005.png │ ├── ADFS-wizard-007.png │ ├── JenkinsURL.png │ ├── SAMLPluginSetting.png │ └── Screen_Shot_2015-12-10_at_16.13.52.png ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── jenkinsci │ │ └── plugins │ │ └── saml │ │ ├── BundleKeyStore.java │ │ ├── IdpMetadataConfiguration.java │ │ ├── OpenSAMLWrapper.java │ │ ├── SamlAdvancedConfiguration.java │ │ ├── SamlAuthenticationToken.java │ │ ├── SamlCrumbExclusion.java │ │ ├── SamlEncryptionData.java │ │ ├── SamlFileResource.java │ │ ├── SamlFileResourceCache.java │ │ ├── SamlFileResourceDisk.java │ │ ├── SamlFormValidation.java │ │ ├── SamlGroupDetails.java │ │ ├── SamlLogoutAction.java │ │ ├── SamlPluginConfig.java │ │ ├── SamlProfileWrapper.java │ │ ├── SamlRedirectActionWrapper.java │ │ ├── SamlSPMetadataWrapper.java │ │ ├── SamlSecurityRealm.java │ │ ├── SamlUserDetails.java │ │ ├── SamlUserDetailsService.java │ │ ├── SamlValidateIdPMetadata.java │ │ ├── UpdateMetadataFromURLPeriodicWork.java │ │ ├── conf │ │ ├── Attribute.java │ │ └── AttributeEntry.java │ │ └── user │ │ ├── LoginDetailsProperty.java │ │ └── SamlCustomProperty.java └── resources │ ├── index.jelly │ ├── log4j.properties │ ├── org │ └── jenkinsci │ │ └── plugins │ │ └── saml │ │ ├── IdpMetadataConfiguration │ │ ├── config.jelly │ │ ├── help-period.html │ │ ├── help-url.html │ │ └── help-xml.html │ │ ├── SamlAdvancedConfiguration │ │ ├── config.jelly │ │ ├── help-authnContextClassRef.html │ │ ├── help-forceAuthn.html │ │ ├── help-nameIdPolicyFormat.html │ │ ├── help-randomRelayState.html │ │ ├── help-spEntityId.html │ │ └── help-useDiskCache.html │ │ ├── SamlEncryptionData │ │ ├── config.jelly │ │ ├── help-forceSignRedirectBindingAuthnRequest.html │ │ ├── help-keyPassword.html │ │ ├── help-keystoreAlias.html │ │ ├── help-keystorePassword.html │ │ ├── help-keystorePath.html │ │ └── help-wantsAssertionsSigned.html │ │ ├── SamlLogoutAction │ │ └── index.jelly │ │ ├── SamlSecurityRealm │ │ ├── config.jelly │ │ ├── help-advancedConfiguration.html │ │ ├── help-binding.html │ │ ├── help-displayNameAttributeName.html │ │ ├── help-emailAttributeName.html │ │ ├── help-encryptionData.html │ │ ├── help-groupsAttributeName.html │ │ ├── help-logoutUrl.html │ │ ├── help-maximumAuthenticationLifetime.html │ │ ├── help-samlCustomAttributes.html │ │ ├── help-usernameAttributeName.html │ │ └── help-usernameCaseConversion.html │ │ ├── conf │ │ └── Attribute │ │ │ └── config.jelly │ │ └── user │ │ ├── LoginDetailsProperty │ │ └── config.jelly │ │ └── SamlCustomProperty │ │ └── config.jelly │ └── samlKeystore.jks └── test ├── java └── org │ └── jenkinsci │ └── plugins │ └── saml │ ├── FakeRequest.java │ ├── LiveTest.java │ ├── OpenSamlWrapperTest.java │ ├── SamlCrumbExclusionTest.java │ ├── SamlFileResourceTest.java │ ├── SamlFormValidationsTest.java │ ├── SamlJCasCCompatibilityTest.java │ └── SamlSecurityRealmTest.java └── resources └── org └── jenkinsci └── plugins └── saml ├── LiveTest ├── config.php ├── docker-compose.yml ├── saml-key.jks ├── saml20-idp-hosted.php └── users.php ├── OpenSamlWrapperTest ├── metadataWrapper │ └── metadata.xml └── profileWrapper │ └── samlresponse.xml ├── SamlCrumbExclusionTest └── testReadSimpleConfiguration │ └── config.xml ├── SamlFileResourceTest └── configuration │ └── config.xml ├── SamlFormValidationsTest └── testReadSimpleConfigurationAdvancedConfiguration │ └── config.xml ├── SamlSecurityRealmTest ├── samlProfileWithEmptyGroups │ └── config.xml ├── testHugeNumberOfUsers │ ├── config.xml │ └── users │ │ ├── tesla │ │ └── config.xml │ │ ├── tesla1 │ │ └── config.xml │ │ ├── tesla10 │ │ └── config.xml │ │ ├── tesla100 │ │ └── config.xml │ │ ├── tesla1000 │ │ └── config.xml │ │ ├── tesla101 │ │ └── config.xml │ │ ├── tesla102 │ │ └── config.xml │ │ ├── tesla103 │ │ └── config.xml │ │ ├── tesla104 │ │ └── config.xml │ │ ├── tesla105 │ │ └── config.xml │ │ ├── tesla106 │ │ └── config.xml │ │ ├── tesla107 │ │ └── config.xml │ │ ├── tesla108 │ │ └── config.xml │ │ ├── tesla109 │ │ └── config.xml │ │ ├── tesla11 │ │ └── config.xml │ │ ├── tesla110 │ │ └── config.xml │ │ ├── tesla111 │ │ └── config.xml │ │ ├── tesla112 │ │ └── config.xml │ │ ├── tesla113 │ │ └── config.xml │ │ ├── tesla114 │ │ └── config.xml │ │ ├── tesla115 │ │ └── config.xml │ │ ├── tesla116 │ │ └── config.xml │ │ ├── tesla117 │ │ └── config.xml │ │ ├── tesla118 │ │ └── config.xml │ │ ├── tesla119 │ │ └── config.xml │ │ ├── tesla12 │ │ └── config.xml │ │ ├── tesla120 │ │ └── config.xml │ │ ├── tesla121 │ │ └── config.xml │ │ ├── tesla122 │ │ └── config.xml │ │ ├── tesla123 │ │ └── config.xml │ │ ├── tesla124 │ │ └── config.xml │ │ ├── tesla125 │ │ └── config.xml │ │ ├── tesla126 │ │ └── config.xml │ │ ├── tesla127 │ │ └── config.xml │ │ ├── tesla128 │ │ └── config.xml │ │ ├── tesla129 │ │ └── config.xml │ │ ├── tesla13 │ │ └── config.xml │ │ ├── tesla130 │ │ └── config.xml │ │ ├── tesla131 │ │ └── config.xml │ │ ├── tesla132 │ │ └── config.xml │ │ ├── tesla133 │ │ └── config.xml │ │ ├── tesla134 │ │ └── config.xml │ │ ├── tesla135 │ │ └── config.xml │ │ ├── tesla136 │ │ └── config.xml │ │ ├── tesla137 │ │ └── config.xml │ │ ├── tesla138 │ │ └── config.xml │ │ ├── tesla139 │ │ └── config.xml │ │ ├── tesla14 │ │ └── config.xml │ │ ├── tesla140 │ │ └── config.xml │ │ ├── tesla141 │ │ └── config.xml │ │ ├── tesla142 │ │ └── config.xml │ │ ├── tesla143 │ │ └── config.xml │ │ ├── tesla144 │ │ └── config.xml │ │ ├── tesla145 │ │ └── config.xml │ │ ├── tesla146 │ │ └── config.xml │ │ ├── tesla147 │ │ └── config.xml │ │ ├── tesla148 │ │ └── config.xml │ │ ├── tesla149 │ │ └── config.xml │ │ ├── tesla15 │ │ └── config.xml │ │ ├── tesla150 │ │ └── config.xml │ │ ├── tesla151 │ │ └── config.xml │ │ ├── tesla152 │ │ └── config.xml │ │ ├── tesla153 │ │ └── config.xml │ │ ├── tesla154 │ │ └── config.xml │ │ ├── tesla155 │ │ └── config.xml │ │ ├── tesla156 │ │ └── config.xml │ │ ├── tesla157 │ │ └── config.xml │ │ ├── tesla158 │ │ └── config.xml │ │ ├── tesla159 │ │ └── config.xml │ │ ├── tesla16 │ │ └── config.xml │ │ ├── tesla160 │ │ └── config.xml │ │ ├── tesla161 │ │ └── config.xml │ │ ├── tesla162 │ │ └── config.xml │ │ ├── tesla163 │ │ └── config.xml │ │ ├── tesla164 │ │ └── config.xml │ │ ├── tesla165 │ │ └── config.xml │ │ ├── tesla166 │ │ └── config.xml │ │ ├── tesla167 │ │ └── config.xml │ │ ├── tesla168 │ │ └── config.xml │ │ ├── tesla169 │ │ └── config.xml │ │ ├── tesla17 │ │ └── config.xml │ │ ├── tesla170 │ │ └── config.xml │ │ ├── tesla171 │ │ └── config.xml │ │ ├── tesla172 │ │ └── config.xml │ │ ├── tesla173 │ │ └── config.xml │ │ ├── tesla174 │ │ └── config.xml │ │ ├── tesla175 │ │ └── config.xml │ │ ├── tesla176 │ │ └── config.xml │ │ ├── tesla177 │ │ └── config.xml │ │ ├── tesla178 │ │ └── config.xml │ │ ├── tesla179 │ │ └── config.xml │ │ ├── tesla18 │ │ └── config.xml │ │ ├── tesla180 │ │ └── config.xml │ │ ├── tesla181 │ │ └── config.xml │ │ ├── tesla182 │ │ └── config.xml │ │ ├── tesla183 │ │ └── config.xml │ │ ├── tesla184 │ │ └── config.xml │ │ ├── tesla185 │ │ └── config.xml │ │ ├── tesla186 │ │ └── config.xml │ │ ├── tesla187 │ │ └── config.xml │ │ ├── tesla188 │ │ └── config.xml │ │ ├── tesla189 │ │ └── config.xml │ │ ├── tesla19 │ │ └── config.xml │ │ ├── tesla190 │ │ └── config.xml │ │ ├── tesla191 │ │ └── config.xml │ │ ├── tesla192 │ │ └── config.xml │ │ ├── tesla193 │ │ └── config.xml │ │ ├── tesla194 │ │ └── config.xml │ │ ├── tesla195 │ │ └── config.xml │ │ ├── tesla196 │ │ └── config.xml │ │ ├── tesla197 │ │ └── config.xml │ │ ├── tesla198 │ │ └── config.xml │ │ ├── tesla199 │ │ └── config.xml │ │ ├── tesla2 │ │ └── config.xml │ │ ├── tesla20 │ │ └── config.xml │ │ ├── tesla200 │ │ └── config.xml │ │ ├── tesla201 │ │ └── config.xml │ │ ├── tesla202 │ │ └── config.xml │ │ ├── tesla203 │ │ └── config.xml │ │ ├── tesla204 │ │ └── config.xml │ │ ├── tesla205 │ │ └── config.xml │ │ ├── tesla206 │ │ └── config.xml │ │ ├── tesla207 │ │ └── config.xml │ │ ├── tesla208 │ │ └── config.xml │ │ ├── tesla209 │ │ └── config.xml │ │ ├── tesla21 │ │ └── config.xml │ │ ├── tesla210 │ │ └── config.xml │ │ ├── tesla211 │ │ └── config.xml │ │ ├── tesla212 │ │ └── config.xml │ │ ├── tesla213 │ │ └── config.xml │ │ ├── tesla214 │ │ └── config.xml │ │ ├── tesla215 │ │ └── config.xml │ │ ├── tesla216 │ │ └── config.xml │ │ ├── tesla217 │ │ └── config.xml │ │ ├── tesla218 │ │ └── config.xml │ │ ├── tesla219 │ │ └── config.xml │ │ ├── tesla22 │ │ └── config.xml │ │ ├── tesla220 │ │ └── config.xml │ │ ├── tesla221 │ │ └── config.xml │ │ ├── tesla222 │ │ └── config.xml │ │ ├── tesla223 │ │ └── config.xml │ │ ├── tesla224 │ │ └── config.xml │ │ ├── tesla225 │ │ └── config.xml │ │ ├── tesla226 │ │ └── config.xml │ │ ├── tesla227 │ │ └── config.xml │ │ ├── tesla228 │ │ └── config.xml │ │ ├── tesla229 │ │ └── config.xml │ │ ├── tesla23 │ │ └── config.xml │ │ ├── tesla230 │ │ └── config.xml │ │ ├── tesla231 │ │ └── config.xml │ │ ├── tesla232 │ │ └── config.xml │ │ ├── tesla233 │ │ └── config.xml │ │ ├── tesla234 │ │ └── config.xml │ │ ├── tesla235 │ │ └── config.xml │ │ ├── tesla236 │ │ └── config.xml │ │ ├── tesla237 │ │ └── config.xml │ │ ├── tesla238 │ │ └── config.xml │ │ ├── tesla239 │ │ └── config.xml │ │ ├── tesla24 │ │ └── config.xml │ │ ├── tesla240 │ │ └── config.xml │ │ ├── tesla241 │ │ └── config.xml │ │ ├── tesla242 │ │ └── config.xml │ │ ├── tesla243 │ │ └── config.xml │ │ ├── tesla244 │ │ └── config.xml │ │ ├── tesla245 │ │ └── config.xml │ │ ├── tesla246 │ │ └── config.xml │ │ ├── tesla247 │ │ └── config.xml │ │ ├── tesla248 │ │ └── config.xml │ │ ├── tesla249 │ │ └── config.xml │ │ ├── tesla25 │ │ └── config.xml │ │ ├── tesla250 │ │ └── config.xml │ │ ├── tesla251 │ │ └── config.xml │ │ ├── tesla252 │ │ └── config.xml │ │ ├── tesla253 │ │ └── config.xml │ │ ├── tesla254 │ │ └── config.xml │ │ ├── tesla255 │ │ └── config.xml │ │ ├── tesla256 │ │ └── config.xml │ │ ├── tesla257 │ │ └── config.xml │ │ ├── tesla258 │ │ └── config.xml │ │ ├── tesla259 │ │ └── config.xml │ │ ├── tesla26 │ │ └── config.xml │ │ ├── tesla260 │ │ └── config.xml │ │ ├── tesla261 │ │ └── config.xml │ │ ├── tesla262 │ │ └── config.xml │ │ ├── tesla263 │ │ └── config.xml │ │ ├── tesla264 │ │ └── config.xml │ │ ├── tesla265 │ │ └── config.xml │ │ ├── tesla266 │ │ └── config.xml │ │ ├── tesla267 │ │ └── config.xml │ │ ├── tesla268 │ │ └── config.xml │ │ ├── tesla269 │ │ └── config.xml │ │ ├── tesla27 │ │ └── config.xml │ │ ├── tesla270 │ │ └── config.xml │ │ ├── tesla271 │ │ └── config.xml │ │ ├── tesla272 │ │ └── config.xml │ │ ├── tesla273 │ │ └── config.xml │ │ ├── tesla274 │ │ └── config.xml │ │ ├── tesla275 │ │ └── config.xml │ │ ├── tesla276 │ │ └── config.xml │ │ ├── tesla277 │ │ └── config.xml │ │ ├── tesla278 │ │ └── config.xml │ │ ├── tesla279 │ │ └── config.xml │ │ ├── tesla28 │ │ └── config.xml │ │ ├── tesla280 │ │ └── config.xml │ │ ├── tesla281 │ │ └── config.xml │ │ ├── tesla282 │ │ └── config.xml │ │ ├── tesla283 │ │ └── config.xml │ │ ├── tesla284 │ │ └── config.xml │ │ ├── tesla285 │ │ └── config.xml │ │ ├── tesla286 │ │ └── config.xml │ │ ├── tesla287 │ │ └── config.xml │ │ ├── tesla288 │ │ └── config.xml │ │ ├── tesla289 │ │ └── config.xml │ │ ├── tesla29 │ │ └── config.xml │ │ ├── tesla290 │ │ └── config.xml │ │ ├── tesla291 │ │ └── config.xml │ │ ├── tesla292 │ │ └── config.xml │ │ ├── tesla293 │ │ └── config.xml │ │ ├── tesla294 │ │ └── config.xml │ │ ├── tesla295 │ │ └── config.xml │ │ ├── tesla296 │ │ └── config.xml │ │ ├── tesla297 │ │ └── config.xml │ │ ├── tesla298 │ │ └── config.xml │ │ ├── tesla299 │ │ └── config.xml │ │ ├── tesla3 │ │ └── config.xml │ │ ├── tesla30 │ │ └── config.xml │ │ ├── tesla300 │ │ └── config.xml │ │ ├── tesla301 │ │ └── config.xml │ │ ├── tesla302 │ │ └── config.xml │ │ ├── tesla303 │ │ └── config.xml │ │ ├── tesla304 │ │ └── config.xml │ │ ├── tesla305 │ │ └── config.xml │ │ ├── tesla306 │ │ └── config.xml │ │ ├── tesla307 │ │ └── config.xml │ │ ├── tesla308 │ │ └── config.xml │ │ ├── tesla309 │ │ └── config.xml │ │ ├── tesla31 │ │ └── config.xml │ │ ├── tesla310 │ │ └── config.xml │ │ ├── tesla311 │ │ └── config.xml │ │ ├── tesla312 │ │ └── config.xml │ │ ├── tesla313 │ │ └── config.xml │ │ ├── tesla314 │ │ └── config.xml │ │ ├── tesla315 │ │ └── config.xml │ │ ├── tesla316 │ │ └── config.xml │ │ ├── tesla317 │ │ └── config.xml │ │ ├── tesla318 │ │ └── config.xml │ │ ├── tesla319 │ │ └── config.xml │ │ ├── tesla32 │ │ └── config.xml │ │ ├── tesla320 │ │ └── config.xml │ │ ├── tesla321 │ │ └── config.xml │ │ ├── tesla322 │ │ └── config.xml │ │ ├── tesla323 │ │ └── config.xml │ │ ├── tesla324 │ │ └── config.xml │ │ ├── tesla325 │ │ └── config.xml │ │ ├── tesla326 │ │ └── config.xml │ │ ├── tesla327 │ │ └── config.xml │ │ ├── tesla328 │ │ └── config.xml │ │ ├── tesla329 │ │ └── config.xml │ │ ├── tesla33 │ │ └── config.xml │ │ ├── tesla330 │ │ └── config.xml │ │ ├── tesla331 │ │ └── config.xml │ │ ├── tesla332 │ │ └── config.xml │ │ ├── tesla333 │ │ └── config.xml │ │ ├── tesla334 │ │ └── config.xml │ │ ├── tesla335 │ │ └── config.xml │ │ ├── tesla336 │ │ └── config.xml │ │ ├── tesla337 │ │ └── config.xml │ │ ├── tesla338 │ │ └── config.xml │ │ ├── tesla339 │ │ └── config.xml │ │ ├── tesla34 │ │ └── config.xml │ │ ├── tesla340 │ │ └── config.xml │ │ ├── tesla341 │ │ └── config.xml │ │ ├── tesla342 │ │ └── config.xml │ │ ├── tesla343 │ │ └── config.xml │ │ ├── tesla344 │ │ └── config.xml │ │ ├── tesla345 │ │ └── config.xml │ │ ├── tesla346 │ │ └── config.xml │ │ ├── tesla347 │ │ └── config.xml │ │ ├── tesla348 │ │ └── config.xml │ │ ├── tesla349 │ │ └── config.xml │ │ ├── tesla35 │ │ └── config.xml │ │ ├── tesla350 │ │ └── config.xml │ │ ├── tesla351 │ │ └── config.xml │ │ ├── tesla352 │ │ └── config.xml │ │ ├── tesla353 │ │ └── config.xml │ │ ├── tesla354 │ │ └── config.xml │ │ ├── tesla355 │ │ └── config.xml │ │ ├── tesla356 │ │ └── config.xml │ │ ├── tesla357 │ │ └── config.xml │ │ ├── tesla358 │ │ └── config.xml │ │ ├── tesla359 │ │ └── config.xml │ │ ├── tesla36 │ │ └── config.xml │ │ ├── tesla360 │ │ └── config.xml │ │ ├── tesla361 │ │ └── config.xml │ │ ├── tesla362 │ │ └── config.xml │ │ ├── tesla363 │ │ └── config.xml │ │ ├── tesla364 │ │ └── config.xml │ │ ├── tesla365 │ │ └── config.xml │ │ ├── tesla366 │ │ └── config.xml │ │ ├── tesla367 │ │ └── config.xml │ │ ├── tesla368 │ │ └── config.xml │ │ ├── tesla369 │ │ └── config.xml │ │ ├── tesla37 │ │ └── config.xml │ │ ├── tesla370 │ │ └── config.xml │ │ ├── tesla371 │ │ └── config.xml │ │ ├── tesla372 │ │ └── config.xml │ │ ├── tesla373 │ │ └── config.xml │ │ ├── tesla374 │ │ └── config.xml │ │ ├── tesla375 │ │ └── config.xml │ │ ├── tesla376 │ │ └── config.xml │ │ ├── tesla377 │ │ └── config.xml │ │ ├── tesla378 │ │ └── config.xml │ │ ├── tesla379 │ │ └── config.xml │ │ ├── tesla38 │ │ └── config.xml │ │ ├── tesla380 │ │ └── config.xml │ │ ├── tesla381 │ │ └── config.xml │ │ ├── tesla382 │ │ └── config.xml │ │ ├── tesla383 │ │ └── config.xml │ │ ├── tesla384 │ │ └── config.xml │ │ ├── tesla385 │ │ └── config.xml │ │ ├── tesla386 │ │ └── config.xml │ │ ├── tesla387 │ │ └── config.xml │ │ ├── tesla388 │ │ └── config.xml │ │ ├── tesla389 │ │ └── config.xml │ │ ├── tesla39 │ │ └── config.xml │ │ ├── tesla390 │ │ └── config.xml │ │ ├── tesla391 │ │ └── config.xml │ │ ├── tesla392 │ │ └── config.xml │ │ ├── tesla393 │ │ └── config.xml │ │ ├── tesla394 │ │ └── config.xml │ │ ├── tesla395 │ │ └── config.xml │ │ ├── tesla396 │ │ └── config.xml │ │ ├── tesla397 │ │ └── config.xml │ │ ├── tesla398 │ │ └── config.xml │ │ ├── tesla399 │ │ └── config.xml │ │ ├── tesla4 │ │ └── config.xml │ │ ├── tesla40 │ │ └── config.xml │ │ ├── tesla400 │ │ └── config.xml │ │ ├── tesla401 │ │ └── config.xml │ │ ├── tesla402 │ │ └── config.xml │ │ ├── tesla403 │ │ └── config.xml │ │ ├── tesla404 │ │ └── config.xml │ │ ├── tesla405 │ │ └── config.xml │ │ ├── tesla406 │ │ └── config.xml │ │ ├── tesla407 │ │ └── config.xml │ │ ├── tesla408 │ │ └── config.xml │ │ ├── tesla409 │ │ └── config.xml │ │ ├── tesla41 │ │ └── config.xml │ │ ├── tesla410 │ │ └── config.xml │ │ ├── tesla411 │ │ └── config.xml │ │ ├── tesla412 │ │ └── config.xml │ │ ├── tesla413 │ │ └── config.xml │ │ ├── tesla414 │ │ └── config.xml │ │ ├── tesla415 │ │ └── config.xml │ │ ├── tesla416 │ │ └── config.xml │ │ ├── tesla417 │ │ └── config.xml │ │ ├── tesla418 │ │ └── config.xml │ │ ├── tesla419 │ │ └── config.xml │ │ ├── tesla42 │ │ └── config.xml │ │ ├── tesla420 │ │ └── config.xml │ │ ├── tesla421 │ │ └── config.xml │ │ ├── tesla422 │ │ └── config.xml │ │ ├── tesla423 │ │ └── config.xml │ │ ├── tesla424 │ │ └── config.xml │ │ ├── tesla425 │ │ └── config.xml │ │ ├── tesla426 │ │ └── config.xml │ │ ├── tesla427 │ │ └── config.xml │ │ ├── tesla428 │ │ └── config.xml │ │ ├── tesla429 │ │ └── config.xml │ │ ├── tesla43 │ │ └── config.xml │ │ ├── tesla430 │ │ └── config.xml │ │ ├── tesla431 │ │ └── config.xml │ │ ├── tesla432 │ │ └── config.xml │ │ ├── tesla433 │ │ └── config.xml │ │ ├── tesla434 │ │ └── config.xml │ │ ├── tesla435 │ │ └── config.xml │ │ ├── tesla436 │ │ └── config.xml │ │ ├── tesla437 │ │ └── config.xml │ │ ├── tesla438 │ │ └── config.xml │ │ ├── tesla439 │ │ └── config.xml │ │ ├── tesla44 │ │ └── config.xml │ │ ├── tesla440 │ │ └── config.xml │ │ ├── tesla441 │ │ └── config.xml │ │ ├── tesla442 │ │ └── config.xml │ │ ├── tesla443 │ │ └── config.xml │ │ ├── tesla444 │ │ └── config.xml │ │ ├── tesla445 │ │ └── config.xml │ │ ├── tesla446 │ │ └── config.xml │ │ ├── tesla447 │ │ └── config.xml │ │ ├── tesla448 │ │ └── config.xml │ │ ├── tesla449 │ │ └── config.xml │ │ ├── tesla45 │ │ └── config.xml │ │ ├── tesla450 │ │ └── config.xml │ │ ├── tesla451 │ │ └── config.xml │ │ ├── tesla452 │ │ └── config.xml │ │ ├── tesla453 │ │ └── config.xml │ │ ├── tesla454 │ │ └── config.xml │ │ ├── tesla455 │ │ └── config.xml │ │ ├── tesla456 │ │ └── config.xml │ │ ├── tesla457 │ │ └── config.xml │ │ ├── tesla458 │ │ └── config.xml │ │ ├── tesla459 │ │ └── config.xml │ │ ├── tesla46 │ │ └── config.xml │ │ ├── tesla460 │ │ └── config.xml │ │ ├── tesla461 │ │ └── config.xml │ │ ├── tesla462 │ │ └── config.xml │ │ ├── tesla463 │ │ └── config.xml │ │ ├── tesla464 │ │ └── config.xml │ │ ├── tesla465 │ │ └── config.xml │ │ ├── tesla466 │ │ └── config.xml │ │ ├── tesla467 │ │ └── config.xml │ │ ├── tesla468 │ │ └── config.xml │ │ ├── tesla469 │ │ └── config.xml │ │ ├── tesla47 │ │ └── config.xml │ │ ├── tesla470 │ │ └── config.xml │ │ ├── tesla471 │ │ └── config.xml │ │ ├── tesla472 │ │ └── config.xml │ │ ├── tesla473 │ │ └── config.xml │ │ ├── tesla474 │ │ └── config.xml │ │ ├── tesla475 │ │ └── config.xml │ │ ├── tesla476 │ │ └── config.xml │ │ ├── tesla477 │ │ └── config.xml │ │ ├── tesla478 │ │ └── config.xml │ │ ├── tesla479 │ │ └── config.xml │ │ ├── tesla48 │ │ └── config.xml │ │ ├── tesla480 │ │ └── config.xml │ │ ├── tesla481 │ │ └── config.xml │ │ ├── tesla482 │ │ └── config.xml │ │ ├── tesla483 │ │ └── config.xml │ │ ├── tesla484 │ │ └── config.xml │ │ ├── tesla485 │ │ └── config.xml │ │ ├── tesla486 │ │ └── config.xml │ │ ├── tesla487 │ │ └── config.xml │ │ ├── tesla488 │ │ └── config.xml │ │ ├── tesla489 │ │ └── config.xml │ │ ├── tesla49 │ │ └── config.xml │ │ ├── tesla490 │ │ └── config.xml │ │ ├── tesla491 │ │ └── config.xml │ │ ├── tesla492 │ │ └── config.xml │ │ ├── tesla493 │ │ └── config.xml │ │ ├── tesla494 │ │ └── config.xml │ │ ├── tesla495 │ │ └── config.xml │ │ ├── tesla496 │ │ └── config.xml │ │ ├── tesla497 │ │ └── config.xml │ │ ├── tesla498 │ │ └── config.xml │ │ ├── tesla499 │ │ └── config.xml │ │ ├── tesla5 │ │ └── config.xml │ │ ├── tesla50 │ │ └── config.xml │ │ ├── tesla500 │ │ └── config.xml │ │ ├── tesla501 │ │ └── config.xml │ │ ├── tesla502 │ │ └── config.xml │ │ ├── tesla503 │ │ └── config.xml │ │ ├── tesla504 │ │ └── config.xml │ │ ├── tesla505 │ │ └── config.xml │ │ ├── tesla506 │ │ └── config.xml │ │ ├── tesla507 │ │ └── config.xml │ │ ├── tesla508 │ │ └── config.xml │ │ ├── tesla509 │ │ └── config.xml │ │ ├── tesla51 │ │ └── config.xml │ │ ├── tesla510 │ │ └── config.xml │ │ ├── tesla511 │ │ └── config.xml │ │ ├── tesla512 │ │ └── config.xml │ │ ├── tesla513 │ │ └── config.xml │ │ ├── tesla514 │ │ └── config.xml │ │ ├── tesla515 │ │ └── config.xml │ │ ├── tesla516 │ │ └── config.xml │ │ ├── tesla517 │ │ └── config.xml │ │ ├── tesla518 │ │ └── config.xml │ │ ├── tesla519 │ │ └── config.xml │ │ ├── tesla52 │ │ └── config.xml │ │ ├── tesla520 │ │ └── config.xml │ │ ├── tesla521 │ │ └── config.xml │ │ ├── tesla522 │ │ └── config.xml │ │ ├── tesla523 │ │ └── config.xml │ │ ├── tesla524 │ │ └── config.xml │ │ ├── tesla525 │ │ └── config.xml │ │ ├── tesla526 │ │ └── config.xml │ │ ├── tesla527 │ │ └── config.xml │ │ ├── tesla528 │ │ └── config.xml │ │ ├── tesla529 │ │ └── config.xml │ │ ├── tesla53 │ │ └── config.xml │ │ ├── tesla530 │ │ └── config.xml │ │ ├── tesla531 │ │ └── config.xml │ │ ├── tesla532 │ │ └── config.xml │ │ ├── tesla533 │ │ └── config.xml │ │ ├── tesla534 │ │ └── config.xml │ │ ├── tesla535 │ │ └── config.xml │ │ ├── tesla536 │ │ └── config.xml │ │ ├── tesla537 │ │ └── config.xml │ │ ├── tesla538 │ │ └── config.xml │ │ ├── tesla539 │ │ └── config.xml │ │ ├── tesla54 │ │ └── config.xml │ │ ├── tesla540 │ │ └── config.xml │ │ ├── tesla541 │ │ └── config.xml │ │ ├── tesla542 │ │ └── config.xml │ │ ├── tesla543 │ │ └── config.xml │ │ ├── tesla544 │ │ └── config.xml │ │ ├── tesla545 │ │ └── config.xml │ │ ├── tesla546 │ │ └── config.xml │ │ ├── tesla547 │ │ └── config.xml │ │ ├── tesla548 │ │ └── config.xml │ │ ├── tesla549 │ │ └── config.xml │ │ ├── tesla55 │ │ └── config.xml │ │ ├── tesla550 │ │ └── config.xml │ │ ├── tesla551 │ │ └── config.xml │ │ ├── tesla552 │ │ └── config.xml │ │ ├── tesla553 │ │ └── config.xml │ │ ├── tesla554 │ │ └── config.xml │ │ ├── tesla555 │ │ └── config.xml │ │ ├── tesla556 │ │ └── config.xml │ │ ├── tesla557 │ │ └── config.xml │ │ ├── tesla558 │ │ └── config.xml │ │ ├── tesla559 │ │ └── config.xml │ │ ├── tesla56 │ │ └── config.xml │ │ ├── tesla560 │ │ └── config.xml │ │ ├── tesla561 │ │ └── config.xml │ │ ├── tesla562 │ │ └── config.xml │ │ ├── tesla563 │ │ └── config.xml │ │ ├── tesla564 │ │ └── config.xml │ │ ├── tesla565 │ │ └── config.xml │ │ ├── tesla566 │ │ └── config.xml │ │ ├── tesla567 │ │ └── config.xml │ │ ├── tesla568 │ │ └── config.xml │ │ ├── tesla569 │ │ └── config.xml │ │ ├── tesla57 │ │ └── config.xml │ │ ├── tesla570 │ │ └── config.xml │ │ ├── tesla571 │ │ └── config.xml │ │ ├── tesla572 │ │ └── config.xml │ │ ├── tesla573 │ │ └── config.xml │ │ ├── tesla574 │ │ └── config.xml │ │ ├── tesla575 │ │ └── config.xml │ │ ├── tesla576 │ │ └── config.xml │ │ ├── tesla577 │ │ └── config.xml │ │ ├── tesla578 │ │ └── config.xml │ │ ├── tesla579 │ │ └── config.xml │ │ ├── tesla58 │ │ └── config.xml │ │ ├── tesla580 │ │ └── config.xml │ │ ├── tesla581 │ │ └── config.xml │ │ ├── tesla582 │ │ └── config.xml │ │ ├── tesla583 │ │ └── config.xml │ │ ├── tesla584 │ │ └── config.xml │ │ ├── tesla585 │ │ └── config.xml │ │ ├── tesla586 │ │ └── config.xml │ │ ├── tesla587 │ │ └── config.xml │ │ ├── tesla588 │ │ └── config.xml │ │ ├── tesla589 │ │ └── config.xml │ │ ├── tesla59 │ │ └── config.xml │ │ ├── tesla590 │ │ └── config.xml │ │ ├── tesla591 │ │ └── config.xml │ │ ├── tesla592 │ │ └── config.xml │ │ ├── tesla593 │ │ └── config.xml │ │ ├── tesla594 │ │ └── config.xml │ │ ├── tesla595 │ │ └── config.xml │ │ ├── tesla596 │ │ └── config.xml │ │ ├── tesla597 │ │ └── config.xml │ │ ├── tesla598 │ │ └── config.xml │ │ ├── tesla599 │ │ └── config.xml │ │ ├── tesla6 │ │ └── config.xml │ │ ├── tesla60 │ │ └── config.xml │ │ ├── tesla600 │ │ └── config.xml │ │ ├── tesla601 │ │ └── config.xml │ │ ├── tesla602 │ │ └── config.xml │ │ ├── tesla603 │ │ └── config.xml │ │ ├── tesla604 │ │ └── config.xml │ │ ├── tesla605 │ │ └── config.xml │ │ ├── tesla606 │ │ └── config.xml │ │ ├── tesla607 │ │ └── config.xml │ │ ├── tesla608 │ │ └── config.xml │ │ ├── tesla609 │ │ └── config.xml │ │ ├── tesla61 │ │ └── config.xml │ │ ├── tesla610 │ │ └── config.xml │ │ ├── tesla611 │ │ └── config.xml │ │ ├── tesla612 │ │ └── config.xml │ │ ├── tesla613 │ │ └── config.xml │ │ ├── tesla614 │ │ └── config.xml │ │ ├── tesla615 │ │ └── config.xml │ │ ├── tesla616 │ │ └── config.xml │ │ ├── tesla617 │ │ └── config.xml │ │ ├── tesla618 │ │ └── config.xml │ │ ├── tesla619 │ │ └── config.xml │ │ ├── tesla62 │ │ └── config.xml │ │ ├── tesla620 │ │ └── config.xml │ │ ├── tesla621 │ │ └── config.xml │ │ ├── tesla622 │ │ └── config.xml │ │ ├── tesla623 │ │ └── config.xml │ │ ├── tesla624 │ │ └── config.xml │ │ ├── tesla625 │ │ └── config.xml │ │ ├── tesla626 │ │ └── config.xml │ │ ├── tesla627 │ │ └── config.xml │ │ ├── tesla628 │ │ └── config.xml │ │ ├── tesla629 │ │ └── config.xml │ │ ├── tesla63 │ │ └── config.xml │ │ ├── tesla630 │ │ └── config.xml │ │ ├── tesla631 │ │ └── config.xml │ │ ├── tesla632 │ │ └── config.xml │ │ ├── tesla633 │ │ └── config.xml │ │ ├── tesla634 │ │ └── config.xml │ │ ├── tesla635 │ │ └── config.xml │ │ ├── tesla636 │ │ └── config.xml │ │ ├── tesla637 │ │ └── config.xml │ │ ├── tesla638 │ │ └── config.xml │ │ ├── tesla639 │ │ └── config.xml │ │ ├── tesla64 │ │ └── config.xml │ │ ├── tesla640 │ │ └── config.xml │ │ ├── tesla641 │ │ └── config.xml │ │ ├── tesla642 │ │ └── config.xml │ │ ├── tesla643 │ │ └── config.xml │ │ ├── tesla644 │ │ └── config.xml │ │ ├── tesla645 │ │ └── config.xml │ │ ├── tesla646 │ │ └── config.xml │ │ ├── tesla647 │ │ └── config.xml │ │ ├── tesla648 │ │ └── config.xml │ │ ├── tesla649 │ │ └── config.xml │ │ ├── tesla65 │ │ └── config.xml │ │ ├── tesla650 │ │ └── config.xml │ │ ├── tesla651 │ │ └── config.xml │ │ ├── tesla652 │ │ └── config.xml │ │ ├── tesla653 │ │ └── config.xml │ │ ├── tesla654 │ │ └── config.xml │ │ ├── tesla655 │ │ └── config.xml │ │ ├── tesla656 │ │ └── config.xml │ │ ├── tesla657 │ │ └── config.xml │ │ ├── tesla658 │ │ └── config.xml │ │ ├── tesla659 │ │ └── config.xml │ │ ├── tesla66 │ │ └── config.xml │ │ ├── tesla660 │ │ └── config.xml │ │ ├── tesla661 │ │ └── config.xml │ │ ├── tesla662 │ │ └── config.xml │ │ ├── tesla663 │ │ └── config.xml │ │ ├── tesla664 │ │ └── config.xml │ │ ├── tesla665 │ │ └── config.xml │ │ ├── tesla666 │ │ └── config.xml │ │ ├── tesla667 │ │ └── config.xml │ │ ├── tesla668 │ │ └── config.xml │ │ ├── tesla669 │ │ └── config.xml │ │ ├── tesla67 │ │ └── config.xml │ │ ├── tesla670 │ │ └── config.xml │ │ ├── tesla671 │ │ └── config.xml │ │ ├── tesla672 │ │ └── config.xml │ │ ├── tesla673 │ │ └── config.xml │ │ ├── tesla674 │ │ └── config.xml │ │ ├── tesla675 │ │ └── config.xml │ │ ├── tesla676 │ │ └── config.xml │ │ ├── tesla677 │ │ └── config.xml │ │ ├── tesla678 │ │ └── config.xml │ │ ├── tesla679 │ │ └── config.xml │ │ ├── tesla68 │ │ └── config.xml │ │ ├── tesla680 │ │ └── config.xml │ │ ├── tesla681 │ │ └── config.xml │ │ ├── tesla682 │ │ └── config.xml │ │ ├── tesla683 │ │ └── config.xml │ │ ├── tesla684 │ │ └── config.xml │ │ ├── tesla685 │ │ └── config.xml │ │ ├── tesla686 │ │ └── config.xml │ │ ├── tesla687 │ │ └── config.xml │ │ ├── tesla688 │ │ └── config.xml │ │ ├── tesla689 │ │ └── config.xml │ │ ├── tesla69 │ │ └── config.xml │ │ ├── tesla690 │ │ └── config.xml │ │ ├── tesla691 │ │ └── config.xml │ │ ├── tesla692 │ │ └── config.xml │ │ ├── tesla693 │ │ └── config.xml │ │ ├── tesla694 │ │ └── config.xml │ │ ├── tesla695 │ │ └── config.xml │ │ ├── tesla696 │ │ └── config.xml │ │ ├── tesla697 │ │ └── config.xml │ │ ├── tesla698 │ │ └── config.xml │ │ ├── tesla699 │ │ └── config.xml │ │ ├── tesla7 │ │ └── config.xml │ │ ├── tesla70 │ │ └── config.xml │ │ ├── tesla700 │ │ └── config.xml │ │ ├── tesla701 │ │ └── config.xml │ │ ├── tesla702 │ │ └── config.xml │ │ ├── tesla703 │ │ └── config.xml │ │ ├── tesla704 │ │ └── config.xml │ │ ├── tesla705 │ │ └── config.xml │ │ ├── tesla706 │ │ └── config.xml │ │ ├── tesla707 │ │ └── config.xml │ │ ├── tesla708 │ │ └── config.xml │ │ ├── tesla709 │ │ └── config.xml │ │ ├── tesla71 │ │ └── config.xml │ │ ├── tesla710 │ │ └── config.xml │ │ ├── tesla711 │ │ └── config.xml │ │ ├── tesla712 │ │ └── config.xml │ │ ├── tesla713 │ │ └── config.xml │ │ ├── tesla714 │ │ └── config.xml │ │ ├── tesla715 │ │ └── config.xml │ │ ├── tesla716 │ │ └── config.xml │ │ ├── tesla717 │ │ └── config.xml │ │ ├── tesla718 │ │ └── config.xml │ │ ├── tesla719 │ │ └── config.xml │ │ ├── tesla72 │ │ └── config.xml │ │ ├── tesla720 │ │ └── config.xml │ │ ├── tesla721 │ │ └── config.xml │ │ ├── tesla722 │ │ └── config.xml │ │ ├── tesla723 │ │ └── config.xml │ │ ├── tesla724 │ │ └── config.xml │ │ ├── tesla725 │ │ └── config.xml │ │ ├── tesla726 │ │ └── config.xml │ │ ├── tesla727 │ │ └── config.xml │ │ ├── tesla728 │ │ └── config.xml │ │ ├── tesla729 │ │ └── config.xml │ │ ├── tesla73 │ │ └── config.xml │ │ ├── tesla730 │ │ └── config.xml │ │ ├── tesla731 │ │ └── config.xml │ │ ├── tesla732 │ │ └── config.xml │ │ ├── tesla733 │ │ └── config.xml │ │ ├── tesla734 │ │ └── config.xml │ │ ├── tesla735 │ │ └── config.xml │ │ ├── tesla736 │ │ └── config.xml │ │ ├── tesla737 │ │ └── config.xml │ │ ├── tesla738 │ │ └── config.xml │ │ ├── tesla739 │ │ └── config.xml │ │ ├── tesla74 │ │ └── config.xml │ │ ├── tesla740 │ │ └── config.xml │ │ ├── tesla741 │ │ └── config.xml │ │ ├── tesla742 │ │ └── config.xml │ │ ├── tesla743 │ │ └── config.xml │ │ ├── tesla744 │ │ └── config.xml │ │ ├── tesla745 │ │ └── config.xml │ │ ├── tesla746 │ │ └── config.xml │ │ ├── tesla747 │ │ └── config.xml │ │ ├── tesla748 │ │ └── config.xml │ │ ├── tesla749 │ │ └── config.xml │ │ ├── tesla75 │ │ └── config.xml │ │ ├── tesla750 │ │ └── config.xml │ │ ├── tesla751 │ │ └── config.xml │ │ ├── tesla752 │ │ └── config.xml │ │ ├── tesla753 │ │ └── config.xml │ │ ├── tesla754 │ │ └── config.xml │ │ ├── tesla755 │ │ └── config.xml │ │ ├── tesla756 │ │ └── config.xml │ │ ├── tesla757 │ │ └── config.xml │ │ ├── tesla758 │ │ └── config.xml │ │ ├── tesla759 │ │ └── config.xml │ │ ├── tesla76 │ │ └── config.xml │ │ ├── tesla760 │ │ └── config.xml │ │ ├── tesla761 │ │ └── config.xml │ │ ├── tesla762 │ │ └── config.xml │ │ ├── tesla763 │ │ └── config.xml │ │ ├── tesla764 │ │ └── config.xml │ │ ├── tesla765 │ │ └── config.xml │ │ ├── tesla766 │ │ └── config.xml │ │ ├── tesla767 │ │ └── config.xml │ │ ├── tesla768 │ │ └── config.xml │ │ ├── tesla769 │ │ └── config.xml │ │ ├── tesla77 │ │ └── config.xml │ │ ├── tesla770 │ │ └── config.xml │ │ ├── tesla771 │ │ └── config.xml │ │ ├── tesla772 │ │ └── config.xml │ │ ├── tesla773 │ │ └── config.xml │ │ ├── tesla774 │ │ └── config.xml │ │ ├── tesla775 │ │ └── config.xml │ │ ├── tesla776 │ │ └── config.xml │ │ ├── tesla777 │ │ └── config.xml │ │ ├── tesla778 │ │ └── config.xml │ │ ├── tesla779 │ │ └── config.xml │ │ ├── tesla78 │ │ └── config.xml │ │ ├── tesla780 │ │ └── config.xml │ │ ├── tesla781 │ │ └── config.xml │ │ ├── tesla782 │ │ └── config.xml │ │ ├── tesla783 │ │ └── config.xml │ │ ├── tesla784 │ │ └── config.xml │ │ ├── tesla785 │ │ └── config.xml │ │ ├── tesla786 │ │ └── config.xml │ │ ├── tesla787 │ │ └── config.xml │ │ ├── tesla788 │ │ └── config.xml │ │ ├── tesla789 │ │ └── config.xml │ │ ├── tesla79 │ │ └── config.xml │ │ ├── tesla790 │ │ └── config.xml │ │ ├── tesla791 │ │ └── config.xml │ │ ├── tesla792 │ │ └── config.xml │ │ ├── tesla793 │ │ └── config.xml │ │ ├── tesla794 │ │ └── config.xml │ │ ├── tesla795 │ │ └── config.xml │ │ ├── tesla796 │ │ └── config.xml │ │ ├── tesla797 │ │ └── config.xml │ │ ├── tesla798 │ │ └── config.xml │ │ ├── tesla799 │ │ └── config.xml │ │ ├── tesla8 │ │ └── config.xml │ │ ├── tesla80 │ │ └── config.xml │ │ ├── tesla800 │ │ └── config.xml │ │ ├── tesla801 │ │ └── config.xml │ │ ├── tesla802 │ │ └── config.xml │ │ ├── tesla803 │ │ └── config.xml │ │ ├── tesla804 │ │ └── config.xml │ │ ├── tesla805 │ │ └── config.xml │ │ ├── tesla806 │ │ └── config.xml │ │ ├── tesla807 │ │ └── config.xml │ │ ├── tesla808 │ │ └── config.xml │ │ ├── tesla809 │ │ └── config.xml │ │ ├── tesla81 │ │ └── config.xml │ │ ├── tesla810 │ │ └── config.xml │ │ ├── tesla811 │ │ └── config.xml │ │ ├── tesla812 │ │ └── config.xml │ │ ├── tesla813 │ │ └── config.xml │ │ ├── tesla814 │ │ └── config.xml │ │ ├── tesla815 │ │ └── config.xml │ │ ├── tesla816 │ │ └── config.xml │ │ ├── tesla817 │ │ └── config.xml │ │ ├── tesla818 │ │ └── config.xml │ │ ├── tesla819 │ │ └── config.xml │ │ ├── tesla82 │ │ └── config.xml │ │ ├── tesla820 │ │ └── config.xml │ │ ├── tesla821 │ │ └── config.xml │ │ ├── tesla822 │ │ └── config.xml │ │ ├── tesla823 │ │ └── config.xml │ │ ├── tesla824 │ │ └── config.xml │ │ ├── tesla825 │ │ └── config.xml │ │ ├── tesla826 │ │ └── config.xml │ │ ├── tesla827 │ │ └── config.xml │ │ ├── tesla828 │ │ └── config.xml │ │ ├── tesla829 │ │ └── config.xml │ │ ├── tesla83 │ │ └── config.xml │ │ ├── tesla830 │ │ └── config.xml │ │ ├── tesla831 │ │ └── config.xml │ │ ├── tesla832 │ │ └── config.xml │ │ ├── tesla833 │ │ └── config.xml │ │ ├── tesla834 │ │ └── config.xml │ │ ├── tesla835 │ │ └── config.xml │ │ ├── tesla836 │ │ └── config.xml │ │ ├── tesla837 │ │ └── config.xml │ │ ├── tesla838 │ │ └── config.xml │ │ ├── tesla839 │ │ └── config.xml │ │ ├── tesla84 │ │ └── config.xml │ │ ├── tesla840 │ │ └── config.xml │ │ ├── tesla841 │ │ └── config.xml │ │ ├── tesla842 │ │ └── config.xml │ │ ├── tesla843 │ │ └── config.xml │ │ ├── tesla844 │ │ └── config.xml │ │ ├── tesla845 │ │ └── config.xml │ │ ├── tesla846 │ │ └── config.xml │ │ ├── tesla847 │ │ └── config.xml │ │ ├── tesla848 │ │ └── config.xml │ │ ├── tesla849 │ │ └── config.xml │ │ ├── tesla85 │ │ └── config.xml │ │ ├── tesla850 │ │ └── config.xml │ │ ├── tesla851 │ │ └── config.xml │ │ ├── tesla852 │ │ └── config.xml │ │ ├── tesla853 │ │ └── config.xml │ │ ├── tesla854 │ │ └── config.xml │ │ ├── tesla855 │ │ └── config.xml │ │ ├── tesla856 │ │ └── config.xml │ │ ├── tesla857 │ │ └── config.xml │ │ ├── tesla858 │ │ └── config.xml │ │ ├── tesla859 │ │ └── config.xml │ │ ├── tesla86 │ │ └── config.xml │ │ ├── tesla860 │ │ └── config.xml │ │ ├── tesla861 │ │ └── config.xml │ │ ├── tesla862 │ │ └── config.xml │ │ ├── tesla863 │ │ └── config.xml │ │ ├── tesla864 │ │ └── config.xml │ │ ├── tesla865 │ │ └── config.xml │ │ ├── tesla866 │ │ └── config.xml │ │ ├── tesla867 │ │ └── config.xml │ │ ├── tesla868 │ │ └── config.xml │ │ ├── tesla869 │ │ └── config.xml │ │ ├── tesla87 │ │ └── config.xml │ │ ├── tesla870 │ │ └── config.xml │ │ ├── tesla871 │ │ └── config.xml │ │ ├── tesla872 │ │ └── config.xml │ │ ├── tesla873 │ │ └── config.xml │ │ ├── tesla874 │ │ └── config.xml │ │ ├── tesla875 │ │ └── config.xml │ │ ├── tesla876 │ │ └── config.xml │ │ ├── tesla877 │ │ └── config.xml │ │ ├── tesla878 │ │ └── config.xml │ │ ├── tesla879 │ │ └── config.xml │ │ ├── tesla88 │ │ └── config.xml │ │ ├── tesla880 │ │ └── config.xml │ │ ├── tesla881 │ │ └── config.xml │ │ ├── tesla882 │ │ └── config.xml │ │ ├── tesla883 │ │ └── config.xml │ │ ├── tesla884 │ │ └── config.xml │ │ ├── tesla885 │ │ └── config.xml │ │ ├── tesla886 │ │ └── config.xml │ │ ├── tesla887 │ │ └── config.xml │ │ ├── tesla888 │ │ └── config.xml │ │ ├── tesla889 │ │ └── config.xml │ │ ├── tesla89 │ │ └── config.xml │ │ ├── tesla890 │ │ └── config.xml │ │ ├── tesla891 │ │ └── config.xml │ │ ├── tesla892 │ │ └── config.xml │ │ ├── tesla893 │ │ └── config.xml │ │ ├── tesla894 │ │ └── config.xml │ │ ├── tesla895 │ │ └── config.xml │ │ ├── tesla896 │ │ └── config.xml │ │ ├── tesla897 │ │ └── config.xml │ │ ├── tesla898 │ │ └── config.xml │ │ ├── tesla899 │ │ └── config.xml │ │ ├── tesla9 │ │ └── config.xml │ │ ├── tesla90 │ │ └── config.xml │ │ ├── tesla900 │ │ └── config.xml │ │ ├── tesla901 │ │ └── config.xml │ │ ├── tesla902 │ │ └── config.xml │ │ ├── tesla903 │ │ └── config.xml │ │ ├── tesla904 │ │ └── config.xml │ │ ├── tesla905 │ │ └── config.xml │ │ ├── tesla906 │ │ └── config.xml │ │ ├── tesla907 │ │ └── config.xml │ │ ├── tesla908 │ │ └── config.xml │ │ ├── tesla909 │ │ └── config.xml │ │ ├── tesla91 │ │ └── config.xml │ │ ├── tesla910 │ │ └── config.xml │ │ ├── tesla911 │ │ └── config.xml │ │ ├── tesla912 │ │ └── config.xml │ │ ├── tesla913 │ │ └── config.xml │ │ ├── tesla914 │ │ └── config.xml │ │ ├── tesla915 │ │ └── config.xml │ │ ├── tesla916 │ │ └── config.xml │ │ ├── tesla917 │ │ └── config.xml │ │ ├── tesla918 │ │ └── config.xml │ │ ├── tesla919 │ │ └── config.xml │ │ ├── tesla92 │ │ └── config.xml │ │ ├── tesla920 │ │ └── config.xml │ │ ├── tesla921 │ │ └── config.xml │ │ ├── tesla922 │ │ └── config.xml │ │ ├── tesla923 │ │ └── config.xml │ │ ├── tesla924 │ │ └── config.xml │ │ ├── tesla925 │ │ └── config.xml │ │ ├── tesla926 │ │ └── config.xml │ │ ├── tesla927 │ │ └── config.xml │ │ ├── tesla928 │ │ └── config.xml │ │ ├── tesla929 │ │ └── config.xml │ │ ├── tesla93 │ │ └── config.xml │ │ ├── tesla930 │ │ └── config.xml │ │ ├── tesla931 │ │ └── config.xml │ │ ├── tesla932 │ │ └── config.xml │ │ ├── tesla933 │ │ └── config.xml │ │ ├── tesla934 │ │ └── config.xml │ │ ├── tesla935 │ │ └── config.xml │ │ ├── tesla936 │ │ └── config.xml │ │ ├── tesla937 │ │ └── config.xml │ │ ├── tesla938 │ │ └── config.xml │ │ ├── tesla939 │ │ └── config.xml │ │ ├── tesla94 │ │ └── config.xml │ │ ├── tesla940 │ │ └── config.xml │ │ ├── tesla941 │ │ └── config.xml │ │ ├── tesla942 │ │ └── config.xml │ │ ├── tesla943 │ │ └── config.xml │ │ ├── tesla944 │ │ └── config.xml │ │ ├── tesla945 │ │ └── config.xml │ │ ├── tesla946 │ │ └── config.xml │ │ ├── tesla947 │ │ └── config.xml │ │ ├── tesla948 │ │ └── config.xml │ │ ├── tesla949 │ │ └── config.xml │ │ ├── tesla95 │ │ └── config.xml │ │ ├── tesla950 │ │ └── config.xml │ │ ├── tesla951 │ │ └── config.xml │ │ ├── tesla952 │ │ └── config.xml │ │ ├── tesla953 │ │ └── config.xml │ │ ├── tesla954 │ │ └── config.xml │ │ ├── tesla955 │ │ └── config.xml │ │ ├── tesla956 │ │ └── config.xml │ │ ├── tesla957 │ │ └── config.xml │ │ ├── tesla958 │ │ └── config.xml │ │ ├── tesla959 │ │ └── config.xml │ │ ├── tesla96 │ │ └── config.xml │ │ ├── tesla960 │ │ └── config.xml │ │ ├── tesla961 │ │ └── config.xml │ │ ├── tesla962 │ │ └── config.xml │ │ ├── tesla963 │ │ └── config.xml │ │ ├── tesla964 │ │ └── config.xml │ │ ├── tesla965 │ │ └── config.xml │ │ ├── tesla966 │ │ └── config.xml │ │ ├── tesla967 │ │ └── config.xml │ │ ├── tesla968 │ │ └── config.xml │ │ ├── tesla969 │ │ └── config.xml │ │ ├── tesla97 │ │ └── config.xml │ │ ├── tesla970 │ │ └── config.xml │ │ ├── tesla971 │ │ └── config.xml │ │ ├── tesla972 │ │ └── config.xml │ │ ├── tesla973 │ │ └── config.xml │ │ ├── tesla974 │ │ └── config.xml │ │ ├── tesla975 │ │ └── config.xml │ │ ├── tesla976 │ │ └── config.xml │ │ ├── tesla977 │ │ └── config.xml │ │ ├── tesla978 │ │ └── config.xml │ │ ├── tesla979 │ │ └── config.xml │ │ ├── tesla98 │ │ └── config.xml │ │ ├── tesla980 │ │ └── config.xml │ │ ├── tesla981 │ │ └── config.xml │ │ ├── tesla982 │ │ └── config.xml │ │ ├── tesla983 │ │ └── config.xml │ │ ├── tesla984 │ │ └── config.xml │ │ ├── tesla985 │ │ └── config.xml │ │ ├── tesla986 │ │ └── config.xml │ │ ├── tesla987 │ │ └── config.xml │ │ ├── tesla988 │ │ └── config.xml │ │ ├── tesla989 │ │ └── config.xml │ │ ├── tesla99 │ │ └── config.xml │ │ ├── tesla990 │ │ └── config.xml │ │ ├── tesla991 │ │ └── config.xml │ │ ├── tesla992 │ │ └── config.xml │ │ ├── tesla993 │ │ └── config.xml │ │ ├── tesla994 │ │ └── config.xml │ │ ├── tesla995 │ │ └── config.xml │ │ ├── tesla996 │ │ └── config.xml │ │ ├── tesla997 │ │ └── config.xml │ │ ├── tesla998 │ │ └── config.xml │ │ └── tesla999 │ │ └── config.xml ├── testReadSimpleConfiguration │ └── config.xml ├── testReadSimpleConfigurationAdvancedConfiguration │ ├── config.xml │ └── secrets │ │ ├── hudson.util.Secret │ │ ├── jenkins.model.Jenkins.crumbSalt │ │ ├── master.key │ │ └── org.jenkinsci.main.modules.instance_identity.InstanceIdentity.KEY ├── testReadSimpleConfigurationEncryptionData │ ├── config.xml │ └── secrets │ │ ├── hudson.util.Secret │ │ ├── jenkins.model.Jenkins.crumbSalt │ │ ├── master.key │ │ └── org.jenkinsci.main.modules.instance_identity.InstanceIdentity.KEY ├── testReadSimpleConfigurationHTTPPost │ └── config.xml ├── testReadSimpleConfigurationLowercase │ └── config.xml ├── testReadSimpleConfigurationUppercase │ └── config.xml └── upgradeIDPMetadataFileTest │ └── config.xml └── configuration-as-code.yaml /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | See [JENKINS-XXXXX](https://issues.jenkins-ci.org/browse/JENKINS-XXXXX). 2 | 3 | 7 | 8 | ### Submitter checklist 9 | 10 | - [ ] JIRA issue is well described 11 | - [ ] Appropriate autotests or explanation to why this change has no tests 12 | 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "maven" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | groups: 8 | pac4j: 9 | patterns: 10 | - "org.pac4j*" 11 | - "pac4j-*" 12 | - package-ecosystem: "github-actions" 13 | directory: / 14 | schedule: 15 | interval: "daily" 16 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc 2 | # https://www.jenkins.io/doc/developer/publishing/releasing-cd/#release-notes 3 | _extends: .github 4 | 5 | -------------------------------------------------------------------------------- /.github/workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | # Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins 2 | 3 | name: cd 4 | on: 5 | workflow_dispatch: 6 | check_run: 7 | types: 8 | - completed 9 | 10 | jobs: 11 | maven-cd: 12 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1 13 | secrets: 14 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} 15 | MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} 16 | 17 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "main" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "main" ] 20 | schedule: 21 | - cron: '29 15 * * 1' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'java' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v4 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v3 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v3 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v3 73 | with: 74 | category: "/language:${{matrix.language}}" 75 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. 4 | # 5 | # Source repository: https://github.com/actions/dependency-review-action 6 | # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement 7 | name: 'Dependency Review' 8 | on: [pull_request] 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | dependency-review: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: 'Checkout Repository' 18 | uses: actions/checkout@v4 19 | - name: 'Dependency Review' 20 | uses: actions/dependency-review-action@v4 21 | -------------------------------------------------------------------------------- /.github/workflows/jenkins-security-scan.yml: -------------------------------------------------------------------------------- 1 | name: Jenkins Security Scan 2 | on: 3 | push: 4 | branches: 5 | - main 6 | # see https://github.com/jenkins-infra/jenkins-security-scan/issues/3 7 | # pull_request: 8 | # types: [ opened, synchronize, reopened ] 9 | workflow_dispatch: 10 | 11 | jobs: 12 | security-scan: 13 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2 14 | with: 15 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate. 16 | # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default. 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.next 6 | release.properties 7 | 8 | # Jenkins 9 | work 10 | 11 | # Eclipse 12 | .classpath 13 | .project 14 | .settings 15 | 16 | # Intellij IDEA 17 | .idea 18 | *.iml 19 | 20 | # Visual Studio Code 21 | .vscode 22 | -------------------------------------------------------------------------------- /.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.jenkins.tools.incrementals 4 | git-changelist-maven-extension 5 | 1.8 6 | 7 | 8 | -------------------------------------------------------------------------------- /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Pconsume-incrementals 2 | -Pmight-produce-incrementals 3 | -Dchangelist.format=%d.v%s 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ------------------- 3 | 4 | | WARNING: Changelogs have been moved to [GitHub Releases](https://github.com/jenkinsci/saml-plugin/releases) | 5 | |-------------------------------------------------------------------------------------------------------------| 6 | 7 | ### Newer versions 8 | 9 | * See [GitHub Releases](https://github.com/jenkinsci/saml-plugin/releases) 10 | 11 | * 1.1.2 (Dec 16 2018) 12 | * [JENKINS-55216](https://issues.jenkins-ci.org/browse/JENKINS-55216) Remove MaximumSessionLifetime setting 13 | * [JENKINS-55205](https://issues.jenkins-ci.org/browse/JENKINS-55205) Review findbugs error with some OS+JDK 14 | * [JENKINS-55175](https://issues.jenkins-ci.org/browse/JENKINS-55175) SAML Plugin fails PCT in Java 11 15 | * [JENKINS-54247](https://issues.jenkins-ci.org/browse/JENKINS-54247) Add to TROUBLESHOOTING how to backup/restore current keys 16 | 17 | * 1.1.1 (Nov 3 2018) 18 | * [JENKINS-54275](https://issues.jenkins-ci.org/browse/JENKINS-54275) Improvements to manage 'Authentication issue instant is too old' errors 19 | * 1.1.0 (Oct 15 2018) 20 | * [JENKINS-53748](https://issues.jenkins-ci.org/browse/JENKINS-53748) SAML plugin skips Jenkins Proxy Configuration, **If you have configured the Jenkins proxy setting, and you do not want to use the proxy to connect to your IdP you have to add your IdP to no-proxy hosts** 21 | 22 | * 1.0.9 (Sep 25 2018) 23 | * [JENKINS-53487](https://issues.jenkins-ci.org/browse/JENKINS-53487) Periodic Update Occurs Too Frequently 24 | * 1.0.7 (Jun 25, 2018) 25 | * [SECURITY-916 / CVE-2018-1000602](https://jenkins.io/security/advisory/2018-06-25/) HTTP session fixation vulnerability in SAML Plugin 26 | * 1.0.6 (Jun 13, 2018) 27 | * [JENKINS-50749](https://issues.jenkins-ci.org/browse/JENKINS-50749) SAMLException: No valid subject assertion found in response (Azure) 28 | * [JENKINS-50004](https://issues.jenkins-ci.org/browse/JENKINS-50004) No more Oops!!! errors 29 | * [JENKINS-49532](https://issues.jenkins-ci.org/browse/JENKINS-49532) autogenerated keystore should not be kept in temp directory 30 | * [JENKINS-49239](https://issues.jenkins-ci.org/browse/JENKINS-49239) Periodic work running with URL empty 31 | * [JENKINS-47966](https://issues.jenkins-ci.org/browse/JENKINS-47966) Add option to disable request signature in saml plugin >= 1.0.2 32 | * [JENKINS-45437](https://issues.jenkins-ci.org/browse/JENKINS-45437) DomainName attribute 33 | * 1.0.5 (Jan 25, 2018) 34 | * [JENKINS-45857](https://issues.jenkins-ci.org/browse/JENKINS-45857) Support to set the Binding type (Redirection/Post) 35 | * [JENKINS-47850](https://issues.jenkins-ci.org/browse/JENKINS-47850) log SAMLResponse on encoding errors 36 | * [JENKINS-41907](https://issues.jenkins-ci.org/browse/JENKINS-41907) Evaluate to obtain IdP Metadata from URL 37 | * [JENKINS-48031](https://issues.jenkins-ci.org/browse/JENKINS-48031) SAML plugin does not accept xml tag in Idp metadata (azure) 38 | * [JENKINS-48030](https://issues.jenkins-ci.org/browse/JENKINS-48030) SAML Azure AD exception 39 | * [JENKINS-47880](https://issues.jenkins-ci.org/browse/JENKINS-47880) Navigating to /securityRealm/finishLogin manually shows an odd error 40 | * [JENKINS-46063](https://issues.jenkins-ci.org/browse/JENKINS-46063) do not allow blank passwords 41 | * [JENKINS-44992](https://issues.jenkins-ci.org/browse/JENKINS-44992) SamlException after metadata update 42 | * 1.0.4 (Sep 19, 2017) 43 | * [JENKINS-46949](https://issues.jenkins-ci.org/browse/JENKINS-46949) Downgrade bouncycastle-api to 2.16.1 44 | * 1.0.3 (Aug 8, 2017) 45 | * [JENKINS-46007](https://issues.jenkins-ci.org/browse/JENKINS-46007) Use Secret to store keystore & storepass for SamlEncryptionData 46 | * [JENKINS-46039](https://issues.jenkins-ci.org/browse/JENKINS-46039) saml-idp.metadata.xml file not found (regresion) 47 | * 1.0.2 (Aug 4, 2017) 48 | * Requires Java 8 49 | * Requires Jenkins 2.60.1 50 | * [JENKINS-45975](https://issues.jenkins-ci.org/browse/JENKINS-45975) Unit test (also an ATH) 51 | * [JENKINS-45954](https://issues.jenkins-ci.org/browse/JENKINS-45954) improvements over email attribute support 52 | * [JENKINS-40144](https://issues.jenkins-ci.org/browse/JENKINS-40144) Validate configuration form fields 53 | * [JENKINS-39602](https://issues.jenkins-ci.org/browse/JENKINS-39602) upgrade pac4j to 1.9.9 54 | * [JENKINS-43939](https://issues.jenkins-ci.org/browse/JENKINS-43939) Complete the implementation of SecurityRealm 55 | * 0.14 (May 30, 2017) 56 | * [JENKINS-43743](https://issues.jenkins-ci.org/browse/JENKINS-43743) Enable to redirect to a custom logout URL 57 | * [JENKINS-37311](https://issues.jenkins-ci.org/browse/JENKINS-37311) make the logout button works 58 | * [JENKINS-38971](https://issues.jenkins-ci.org/browse/JENKINS-38971) Add support SAML ForceAuthn, AuthnContextClassRef, custom EntityId, and session timeout 59 | * [JENKINS-43736](https://issues.jenkins-ci.org/browse/JENKINS-43736) Enable to set up the user email address using SAML attribute 60 | * [JENKINS-38034](https://issues.jenkins-ci.org/browse/JENKINS-38034) SAML Plugin does not load groups when access with API Token 61 | * 0.13 (Jan 25, 2017) 62 | * [JENKINS-39601](https://issues.jenkins-ci.org/browse/JENKINS-39601) Improve log, now you could set a logger to org.jenkinsci.plugins.saml you can see a verbose trace of the login process 63 | * Incorrect implementation of `loadUserByUsename`, Users are added on demand JENKINS-38228 64 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | buildPlugin(useContainerAgent: false, configurations: [ 4 | [platform: 'linux', jdk: 21], 5 | [platform: 'windows', jdk: 17], 6 | ]) 7 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Jenkins SAML 2.0 Plugin 2 | 3 | This product includes software developed at 4 | Connectifier, Inc. (https://www.connectifier.com/) 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Jenkins SAML Plugin 2 | =================== 3 | 4 | A SAML 2.0 Plugin for the Jenkins Continuous Integration server 5 | 6 | Changelog 7 | ------------------- 8 | * For 1.1.3 and newer versions, see [GitHub Releases](https://github.com/jenkinsci/saml-plugin/releases) 9 | * For previous versions, see [this file](./CHANGELOG.md) 10 | 11 | Configure 12 | ------------------- 13 | [Overall Configurarion](doc/CONFIGURE.md) 14 | 15 | [ADFS Example](doc/ADFS_CONFIG.md) 16 | 17 | [Azure Example](doc/CONFIGURE_AZURE.md) 18 | 19 | Troubleshooting 20 | ------------------- 21 | [Troubleshooting](doc/TROUBLESHOOTING.md) 22 | 23 | Local development 24 | ------------------- 25 | 26 | Run `mvn hpi:run` and visit http://localhost:8080/jenkins/. 27 | You will see the plugin under the "Installed" tab in the Jenkins plugin manager. 28 | 29 | Releasing 30 | ------------------- 31 | 32 | Create `~/.m2/settings.xml` per [plugin tutorial](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial) and include password as described in [hosting plugins](https://wiki.jenkins-ci.org/display/JENKINS/Hosting+Plugins). 33 | Run `mvn release:prepare release:perform` 34 | 35 | Reporting issues 36 | ---------------- 37 | Check first is your issue in [open issues](https://issues.jenkins-ci.org/issues/?jql=project%20%3D%20JENKINS%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20saml-plugin). 38 | Report new issue on https://issues.jenkins-ci.org on component **saml-plugin**. 39 | 40 | [How to report an issue](https://wiki.jenkins.io/display/JENKINS/How+to+report+an+issue) 41 | 42 | **The Jenkins JIRA is not a support site. If you need assistance or have general questions, visit us [in chat](http://jenkins-ci.org/content/chat), or email one of the [mailing lists](http://jenkins-ci.org/content/mailing-lists).** 43 | -------------------------------------------------------------------------------- /doc/ADFS_CONFIG.md: -------------------------------------------------------------------------------- 1 | Example: Setting up Active Directory Federation Services (ADFS) to use with Jenkins 2 | ---------------- 3 | 4 | *Note:* replace adfs.example.com with the name of your ADFS, replace jenkins.example.com with the name of your Jenkins host. 5 | 6 | **On the Jenkins side:** 7 | 8 | * Set the `IdP Metadata URL` to `https://adfs.example.com/FederationMetadata/2007-06/FederationMetadata.xml` 9 | * Set the `Refresh Period` to `1440` (24h, suggested value) 10 | 11 | This allows the SAML plugin to fetch the IdP file from ADFS and should avoid needing to update it when certs/keys change. 12 | 13 | If loading the xml manually, it may be necessary to set the system property `-Dorg.apache.xml.security.ignoreLineBreaks=true` 14 | when starting Jenkins. This does not appear to be necessary when allowing the plugin to fetch the XML directly. 15 | 16 | It is recommended to configure the following attributes, depending on your IdP configuration and preferences the values may be different. 17 | | Attribute | Value | 18 | |--|--| 19 | | Display Name | http://schemas.xmlsoap.org/claims/CommonName | 20 | | Group | http://schemas.xmlsoap.org/claims/Group | 21 | | Email | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress | 22 | 23 | Username is not set as it is using the `Name Id` field. 24 | 25 | **On the Windows side:** 26 | 27 | Open the Management console (mmc), make sure you have the AD FS Management snap-in. Add a Relying Party Trust: 28 | 29 | ![](images/Screen_Shot_2015-12-10_at_16.13.52.png) 30 | 31 | 32 | Using the wizard and the SP metadata URL will make this process very straight forward. The screenshots below are from 33 | the wizard with the verify step omitted. Depending on the ADFS version in use, you may receive the warning shown in the 34 | screenshot. Even if you don't receive the warning it is still a good idea to review all of the parameters. At this time, 35 | there are no known issues with ADFS being able to import and utilize the metadata. 36 | 37 | In the `Choose Access Control Policy` step, choose the appropriate policy to meet your requirements. The 38 | `Permit Everyone` policy was chosen here more for demonstration purposes. 39 | 40 | ![](images/ADFS-wizard-001.png) ![](images/ADFS-wizard-002.png) 41 | 42 | ![](images/ADFS-wizard-003.png) ![](images/ADFS-wizard-004.png) 43 | 44 | ![](images/ADFS-wizard-005.png) ![](images/ADFS-wizard-007.png) 45 | 46 | The second step is to configure the claims. This should be launched automatically by the last step of the wizard. If it 47 | is not, select the entry in the `Relying Part Trusts` and either right click and select `Edit Claim Issuance Policy...` 48 | or click `Edit Claim Issuance Policy...` on the right. These may need to be adjusted based on your environment. The 49 | following are used for demonstration purposes and align with the attributes set in Jenkins. Of note is the group 50 | attribute, the use of `unqualified names` will likely make using this attribute for authorization easier. 51 | 52 | ![](images/ADFS-claim-001.png) 53 | 54 | ![](images/ADFS-claim-002.png) ![](images/ADFS-claim-003.png) 55 | 56 | -------------------------------------------------------------------------------- /doc/CONFIGURE_AZURE.md: -------------------------------------------------------------------------------- 1 | ## Configure Azure 2 | 3 | You have to configure a SSO application on Azure by following the instructions in [Configuring single sign-on to applications that are not in the Azure Active Directory application gallery](https://docs.microsoft.com/en-us/azure/active-directory/active-directory-saas-custom-apps). You will have to take care of the following settings in order to configure Jenkins SAML Plugin properly: 4 | 5 | * **Sign On URL**: it should be the Jenkins base URL Manage, you have to check the value of Jenkins URL setting on `Jenkins/Configure System/Jenkins Location/Jenkins URL` 6 | ![Manage Jenkins/Configure System/Jenkins Location/Jenkins URL](images/JenkinsURL.png) 7 | * **Identifier**: the identifier that you want to use as Entry ID for Jenkins SP (e.g. `JenkinsSP`). 8 | * **Reply URL**: The URL when the SAMLResponse will be sent, it should be like this one `https:///securityRealm/finishLogin` 9 | * **Sign-Out URL**: The URL that you want to use to log-out from your SSO, this will be appear in the IdP Metadata XML like this example 10 | ``` 11 | ) 12 | ``` 13 | * **SAML XML Metadata URL**: the URL that return the IdP metadata XML, it should looks like `https://login.microsoftonline.com//FederationMetadata/2007-06/FederationMetadata.xml` see [Federation metadata](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-federation-metadata) for more details. 14 | * **Binding Protocol**: Azure exposed HTTP-Redirect and HTTP-POST you have to select the Binding protocol, SAML Plugin Latest version support HTTP-Redirect and HTTP-POST 15 | ``` 16 | 17 | 18 | ``` 19 | 20 | You should customize Attributes to send to Jenkins [Customizing claims issued in the SAML token for enterprise applications in Azure Active Directory](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-saml-claims-customization), these are the recommended attributes to setup: 21 | * **User Name**: attribute will be load with the unique user ID (e.g. name=`username` value=`user.userprincipalname`). 22 | * **Display Name**: attribute will be load with the user name to display in the UI (e.g. name=`displayname` value=`user.givenname`). 23 | * **Groups**: attribute will be load with the groups assigned to the user (e.g. name=`groups` value=`user.memberof`). 24 | * **Email**: attribute will be load with the user email address (e.g. name=`email` value=`user.mail`). 25 | 26 | For more detail about Azure configuration take a look at the SAML 2.0 Azure documentation: 27 | 28 | [How Azure Active Directory uses the SAML protocol](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-saml-protocol-reference) 29 | 30 | [Single Sign-On SAML protocol](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-single-sign-on-protocol-reference) 31 | 32 | ## Configure Jenkins 33 | 34 | These are the recommended configuration settings to make Jenkins SAML Plugin work with Azure SSO service. 35 | 36 | * **Metadata** 37 | * **IdP Metadata**: The IdP Metadata XML downloaded from Azure (e.g. `https://login.microsoftonline.com//FederationMetadata/2007-06/FederationMetadata.xml`) see [Federation metadata](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-federation-metadata) for more details (not need if you have set the IdP Metadata URL). 38 | * **IdP Metadata URL**: The URL to download the IdP Metadata XML (e.g. `https://login.microsoftonline.com//FederationMetadata/2007-06/FederationMetadata.xml`) see [Federation metadata](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-federation-metadata) for more details (not need if you have set the IdP Metadata). 39 | * **Refresh Period**: The period of minutes we will wait until refresh the IdP Metadata. Set it to 0 to not update the metadata. 40 | * **Display Name Attribute**: the attribute name that contains the **Display Name** of the user you have set in Azure configuration (e.g. `displayname`). 41 | * **Group Attribute**: the attribute name that contains the **Groups** of the user you have set in Azure configuration (e.g. `groups`). 42 | * **Username Attribute**: the attribute name that contains the **User Name** of the user you have set in Azure configuration (e.g. `username`). 43 | * **Email Attribute**: the attribute name that contains the **Email** of the user you have set in Azure configuration (e.g. `email`). 44 | * **Data Binding Method**: method of redirection binding HTTP-Redirect and HTTP-POST you have set as **Binding Protocol** on Azure configuration. 45 | * **Logout URL**: the URL you have set as **Sign-Out URL** (https://login.microsoftonline.com/common/wsfederation?wa=wsignout1.0). 46 | * **Advanced Configuration** 47 | * **Force Authentication**: if you experience problems with the authentication it is recommended to enable it. 48 | * **SP Entity ID** - value you have set as **Identifier** in the Azure configuration (e.g. `JenkinsSP`). 49 | 50 | For more details about the SAML Plugin configuration take a look at [Configuration Guide](CONFIGURE.md) 51 | -------------------------------------------------------------------------------- /doc/CONFIGURE_KEYCLOAK.md: -------------------------------------------------------------------------------- 1 | # Configure Keycloak 2 | 3 | *Note:* replace https://keycloak.example.com with the root URL of your Keycloak service, replace jenkins.example.com with the name of your Jenkins host. 4 | 5 | ## Retrieve Jenkins Service Provider metadata 6 | 7 | 1. Choose SAML 2.0 as a Security Realm 8 | 2. Set the `IdP Metadata URL` to `https://keycloak.example.com/realms/{realm}/protocol/saml/descriptor`, where `{realm}` is the Realm of your client 9 | 3. Set the `Refresh Period` to `1440` (24h, suggested value) 10 | 4. Click `Validate IdP Metadata` to make sure metadata can be fetched 11 | 5. Click `Apply` 12 | 6. Find `Service Provider Metadata` link and save it as an XML file, e.g., `jenkins-sp-metadata.xml` 13 | 14 | ## Import a new client into Keycloak realm 15 | 16 | [Using an entity descriptor to create a client](https://www.keycloak.org/docs/latest/server_admin/index.html#proc-using-an-entity-descriptors_server_administration_guide) is the reference documentation. 17 | 18 | In a different tab in the Keycloak admin interface: 19 | 20 | 1. On the `Clients` page of the same realm as above chose to `Import client` 21 | 2. Select above `jenkins-sp-metadata.xml` as your `Resource file` 22 | 3. (Optional) Give a meaningful Name and Description 23 | 4. Save 24 | 5. Find "Name ID format" field and change to `username` or `persistent` 25 | 6. Save your change 26 | 27 | ## Add predefined mappers with user details 28 | 29 | In the client details of the newly imported client: 30 | 31 | 1. Switch to `Client scopes` 32 | 2. Open a `dedicated` client scope 33 | 3. `Add predefined mappers` 34 | 4. Choose `X500 email`, `X500 givenName`, `X500 surname` and click `Add` 35 | 5. Open the newly added `X500 email` mapper and note the `SAML Attribute Name`, e.g., `urn:oid:1.2.840.113549.1.9.1` 36 | 6. Repeat previous step for given name or surname depending on your preference of Display Name on the jenkins side, e.g., `urn:oid:2.5.4.42` for given name. 37 | 7. For the sake of an example we will use a predefined `Role list` mapper as a source of groups (`SAML Attribute Name` is `Role`). However, depending on your use case one more mapper might be needed to share group membership with Jenkins. 38 | 39 | ## Complete SAML 2.0 Security Realm configuration 40 | 41 | Back on the Jenkins Security page: 42 | 43 | 1. Set "Email Attribute" to the value noted in step 5 above 44 | 2. Set "Display Name Attribute" to the value noted in step 6 above 45 | 3. Set "Group Attribute" to the value noted in step 7 above 46 | 4. "Save" 47 | 48 | Test the authentication in an Incognito Window or a different browser. 49 | 50 | For more details about the SAML Plugin configuration take a look at [Configuration Guide](CONFIGURE.md) 51 | For troubleshooting steps and know issue see [Troubleshooting](TROUBLESHOOTING.md) 52 | -------------------------------------------------------------------------------- /doc/images/ADFS-claim-001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/ADFS-claim-001.png -------------------------------------------------------------------------------- /doc/images/ADFS-claim-002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/ADFS-claim-002.png -------------------------------------------------------------------------------- /doc/images/ADFS-claim-003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/ADFS-claim-003.png -------------------------------------------------------------------------------- /doc/images/ADFS-wizard-001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/ADFS-wizard-001.png -------------------------------------------------------------------------------- /doc/images/ADFS-wizard-002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/ADFS-wizard-002.png -------------------------------------------------------------------------------- /doc/images/ADFS-wizard-003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/ADFS-wizard-003.png -------------------------------------------------------------------------------- /doc/images/ADFS-wizard-004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/ADFS-wizard-004.png -------------------------------------------------------------------------------- /doc/images/ADFS-wizard-005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/ADFS-wizard-005.png -------------------------------------------------------------------------------- /doc/images/ADFS-wizard-007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/ADFS-wizard-007.png -------------------------------------------------------------------------------- /doc/images/JenkinsURL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/JenkinsURL.png -------------------------------------------------------------------------------- /doc/images/SAMLPluginSetting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/SAMLPluginSetting.png -------------------------------------------------------------------------------- /doc/images/Screen_Shot_2015-12-10_at_16.13.52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/doc/images/Screen_Shot_2015-12-10_at_16.13.52.png -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlAdvancedConfiguration.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import edu.umd.cs.findbugs.annotations.NonNull; 21 | import org.apache.commons.lang.StringUtils; 22 | import org.kohsuke.stapler.DataBoundConstructor; 23 | import org.kohsuke.stapler.DataBoundSetter; 24 | import org.kohsuke.stapler.interceptor.RequirePOST; 25 | import hudson.Extension; 26 | import hudson.Util; 27 | import hudson.model.AbstractDescribableImpl; 28 | import hudson.model.Descriptor; 29 | import hudson.util.FormValidation; 30 | import jenkins.model.Jenkins; 31 | import static org.jenkinsci.plugins.saml.SamlSecurityRealm.ERROR_NOT_VALID_NUMBER; 32 | 33 | /** 34 | * Simple immutable data class to hold the optional advanced configuration data section 35 | * of the plugin's configuration page 36 | */ 37 | public class SamlAdvancedConfiguration extends AbstractDescribableImpl { 38 | private final Boolean forceAuthn; 39 | private final String authnContextClassRef; 40 | private final String spEntityId; 41 | private final String nameIdPolicyFormat; 42 | 43 | private Boolean useDiskCache = false; 44 | 45 | private Boolean randomRelayState = false; 46 | 47 | @DataBoundConstructor 48 | public SamlAdvancedConfiguration(Boolean forceAuthn, 49 | String authnContextClassRef, 50 | String spEntityId, 51 | String nameIdPolicyFormat) { 52 | this.forceAuthn = (forceAuthn != null) ? forceAuthn : false; 53 | this.authnContextClassRef = Util.fixEmptyAndTrim(authnContextClassRef); 54 | this.spEntityId = Util.fixEmptyAndTrim(spEntityId); 55 | this.nameIdPolicyFormat = Util.fixEmptyAndTrim(nameIdPolicyFormat); 56 | } 57 | 58 | public Boolean getForceAuthn() { 59 | return forceAuthn; 60 | } 61 | 62 | public String getAuthnContextClassRef() { 63 | return authnContextClassRef; 64 | } 65 | 66 | public String getSpEntityId() { 67 | return spEntityId; 68 | } 69 | 70 | public String getNameIdPolicyFormat() { 71 | return nameIdPolicyFormat; 72 | } 73 | 74 | public Boolean getUseDiskCache() { 75 | return useDiskCache != null ? useDiskCache : false; 76 | } 77 | 78 | @DataBoundSetter 79 | public void setUseDiskCache(Boolean useDiskCache) { 80 | this.useDiskCache = useDiskCache; 81 | } 82 | 83 | public Boolean getRandomRelayState() { 84 | return randomRelayState != null ? randomRelayState : false; 85 | } 86 | 87 | @DataBoundSetter 88 | public void setRandomRelayState(Boolean randomRelayState) { 89 | this.randomRelayState = randomRelayState; 90 | } 91 | 92 | @Override 93 | public String toString() { 94 | return "SamlAdvancedConfiguration{" + "forceAuthn=" + getForceAuthn() + ", authnContextClassRef='" 95 | + StringUtils.defaultIfBlank(getAuthnContextClassRef(), "none") + '\'' + ", spEntityId='" 96 | + StringUtils.defaultIfBlank(getSpEntityId(), "none") + '\'' + ", nameIdPolicyFormat='" 97 | + StringUtils.defaultIfBlank(getNameIdPolicyFormat(), "none") + '\'' 98 | + ", useDiskCache=" + getUseDiskCache() 99 | + ", randomRelayState=" + getRandomRelayState() + '}'; 100 | } 101 | 102 | @SuppressWarnings("unused") 103 | @Extension 104 | public static final class DescriptorImpl extends Descriptor { 105 | public DescriptorImpl() { 106 | super(); 107 | } 108 | 109 | public DescriptorImpl(Class clazz) { 110 | super(clazz); 111 | } 112 | 113 | @NonNull 114 | @Override 115 | public String getDisplayName() { 116 | return "Advanced Configuration"; 117 | } 118 | 119 | 120 | @RequirePOST 121 | public FormValidation doCheckAuthnContextClassRef(@org.kohsuke.stapler.QueryParameter String authnContextClassRef) { 122 | Jenkins.get().checkPermission(Jenkins.ADMINISTER); 123 | return SamlFormValidation.checkStringFormat(authnContextClassRef); 124 | } 125 | 126 | 127 | @RequirePOST 128 | public FormValidation doCheckSpEntityId(@org.kohsuke.stapler.QueryParameter String spEntityId) { 129 | Jenkins.get().checkPermission(Jenkins.ADMINISTER); 130 | return SamlFormValidation.checkStringFormat(spEntityId); 131 | } 132 | 133 | @RequirePOST 134 | public FormValidation doCheckNameIdPolicyFormat(@org.kohsuke.stapler.QueryParameter String nameIdPolicyFormat) { 135 | Jenkins.get().checkPermission(Jenkins.ADMINISTER); 136 | return SamlFormValidation.checkStringFormat(nameIdPolicyFormat); 137 | } 138 | 139 | @RequirePOST 140 | public FormValidation doCheckMaximumSessionLifetime(@org.kohsuke.stapler.QueryParameter String maximumSessionLifetime) { 141 | Jenkins.get().checkPermission(Jenkins.ADMINISTER); 142 | if (StringUtils.isEmpty(maximumSessionLifetime)) { 143 | return hudson.util.FormValidation.ok(); 144 | } 145 | 146 | long i = 0; 147 | try { 148 | i = Long.parseLong(maximumSessionLifetime); 149 | } catch (NumberFormatException e) { 150 | return hudson.util.FormValidation.error(ERROR_NOT_VALID_NUMBER, e); 151 | } 152 | 153 | if (i < 0) { 154 | return hudson.util.FormValidation.error(ERROR_NOT_VALID_NUMBER); 155 | } 156 | 157 | if (i > Integer.MAX_VALUE) { 158 | return hudson.util.FormValidation.error(ERROR_NOT_VALID_NUMBER); 159 | } 160 | 161 | return hudson.util.FormValidation.ok(); 162 | } 163 | 164 | } 165 | } -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import edu.umd.cs.findbugs.annotations.NonNull; 21 | import org.springframework.security.authentication.AbstractAuthenticationToken; 22 | 23 | /** 24 | * @see AbstractAuthenticationToken 25 | */ 26 | public final class SamlAuthenticationToken extends AbstractAuthenticationToken { 27 | 28 | private static final long serialVersionUID = 2L; 29 | 30 | private final SamlUserDetails userDetails; 31 | 32 | public SamlAuthenticationToken(@NonNull SamlUserDetails userDetails) { 33 | super(userDetails.getAuthorities()); 34 | this.userDetails = userDetails; 35 | this.setDetails(userDetails); 36 | this.setAuthenticated(true); 37 | } 38 | 39 | public SamlUserDetails getPrincipal() { 40 | return userDetails; 41 | } 42 | 43 | public String getCredentials() { 44 | return "SAML does not use passwords"; 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlCrumbExclusion.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.saml; 2 | 3 | import java.io.IOException; 4 | import java.util.logging.Logger; 5 | import jakarta.servlet.FilterChain; 6 | import jakarta.servlet.ServletException; 7 | import jakarta.servlet.http.HttpServletRequest; 8 | import jakarta.servlet.http.HttpServletResponse; 9 | import hudson.Extension; 10 | import hudson.security.csrf.CrumbExclusion; 11 | 12 | /** 13 | * @see hudson.security.csrf.CrumbExclusion 14 | */ 15 | @Extension 16 | public class SamlCrumbExclusion extends CrumbExclusion { 17 | private static final Logger LOG = Logger.getLogger(SamlCrumbExclusion.class.getName()); 18 | 19 | @Override 20 | public boolean process(HttpServletRequest request, HttpServletResponse response, FilterChain chain) 21 | throws IOException, ServletException { 22 | jenkins.model.Jenkins j = jenkins.model.Jenkins.get(); 23 | if (j.getSecurityRealm() instanceof SamlSecurityRealm 24 | && shouldExclude(request.getPathInfo())) { 25 | chain.doFilter(request, response); 26 | return true; 27 | } 28 | return false; 29 | } 30 | 31 | private static boolean shouldExclude(String pathInfo) { 32 | if (pathInfo == null) { 33 | LOG.fine("SamlCrumbExclusion.shouldExclude empty"); 34 | return false; 35 | } 36 | if (pathInfo.startsWith("/" + SamlSecurityRealm.CONSUMER_SERVICE_URL_PATH)) { 37 | LOG.fine("SamlCrumbExclusion.shouldExclude excluding '" + pathInfo + "'"); 38 | return true; 39 | } else { 40 | LOG.finer("SamlCrumbExclusion.shouldExclude keeping '" + pathInfo + "'"); 41 | return false; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlFileResource.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import java.io.File; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.OutputStream; 24 | import java.net.URI; 25 | import java.net.URL; 26 | 27 | import org.apache.commons.lang.NotImplementedException; 28 | import org.springframework.core.io.Resource; 29 | import org.springframework.core.io.WritableResource; 30 | 31 | import edu.umd.cs.findbugs.annotations.NonNull; 32 | 33 | /** 34 | * Class to manage the metadata files. 35 | */ 36 | class SamlFileResource implements WritableResource { 37 | 38 | private final WritableResource resource; 39 | 40 | public SamlFileResource(@NonNull String fileName) { 41 | if(getUseDiskCache()){ 42 | this.resource = new SamlFileResourceCache(fileName); 43 | } else { 44 | this.resource = new SamlFileResourceDisk(fileName); 45 | } 46 | } 47 | 48 | public SamlFileResource(@NonNull String fileName, @NonNull String data) { 49 | if(getUseDiskCache()){ 50 | this.resource = new SamlFileResourceCache(fileName, data); 51 | } else { 52 | this.resource = new SamlFileResourceDisk(fileName, data); 53 | } 54 | } 55 | 56 | private boolean getUseDiskCache() { 57 | boolean ret = false; 58 | jenkins.model.Jenkins j = jenkins.model.Jenkins.get(); 59 | if (j.getSecurityRealm() instanceof SamlSecurityRealm) { 60 | SamlSecurityRealm samlSecurityRealm = (SamlSecurityRealm) j.getSecurityRealm(); 61 | SamlAdvancedConfiguration config = samlSecurityRealm.getAdvancedConfiguration(); 62 | if(config != null ) { 63 | ret = config.getUseDiskCache(); 64 | } 65 | } 66 | return ret; 67 | } 68 | 69 | @Override 70 | public boolean exists() { 71 | return resource.exists(); 72 | } 73 | 74 | @Override 75 | public boolean isReadable() { 76 | return resource.isReadable(); 77 | } 78 | 79 | @Override 80 | public boolean isOpen() { 81 | return false; 82 | } 83 | 84 | @NonNull 85 | @Override 86 | public URL getURL() throws IOException { 87 | return resource.getURL(); 88 | } 89 | 90 | @NonNull 91 | @Override 92 | public URI getURI() throws IOException { 93 | return resource.getURI(); 94 | } 95 | 96 | @Override 97 | public String getFilename() { 98 | return resource.getFilename(); 99 | } 100 | 101 | @NonNull 102 | @Override 103 | public String getDescription() { 104 | return resource.getDescription(); 105 | } 106 | 107 | @NonNull 108 | @Override 109 | public InputStream getInputStream() throws IOException { 110 | return resource.getInputStream(); 111 | } 112 | 113 | @NonNull 114 | @Override 115 | public File getFile() throws IOException { 116 | return resource.getFile(); 117 | } 118 | 119 | @Override 120 | public long contentLength() throws IOException { 121 | return resource.contentLength(); 122 | } 123 | 124 | @Override 125 | public long lastModified() throws IOException { 126 | return resource.lastModified(); 127 | } 128 | 129 | @NonNull 130 | @Override 131 | public Resource createRelative(@NonNull String s) { 132 | throw new NotImplementedException(); 133 | } 134 | 135 | @Override 136 | public boolean isWritable() { 137 | return resource.isWritable(); 138 | } 139 | 140 | @NonNull 141 | @Override 142 | public OutputStream getOutputStream() throws IOException { 143 | return resource.getOutputStream(); 144 | } 145 | } -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlFileResourceCache.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import org.apache.commons.io.FileUtils; 21 | import org.apache.commons.io.IOUtils; 22 | import org.apache.commons.lang.NotImplementedException; 23 | import org.pac4j.core.exception.TechnicalException; 24 | import org.springframework.core.io.Resource; 25 | import org.springframework.core.io.WritableResource; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import java.io.ByteArrayOutputStream; 29 | import java.io.File; 30 | import java.io.IOException; 31 | import java.io.InputStream; 32 | import java.io.OutputStream; 33 | import java.io.UnsupportedEncodingException; 34 | import java.net.MalformedURLException; 35 | import java.net.URI; 36 | import java.net.URL; 37 | import java.nio.file.Files; 38 | import java.util.HashMap; 39 | import java.util.Map; 40 | import java.util.logging.Level; 41 | import java.util.logging.Logger; 42 | 43 | /** 44 | * Class to manage the metadata files using cache. 45 | * It will only write the files if the content is different. 46 | */ 47 | class SamlFileResourceCache implements WritableResource { 48 | 49 | private static final Logger LOG = Logger.getLogger(SamlFileResource.class.getName()); 50 | 51 | private String fileName; 52 | 53 | private final static Map cache = new HashMap<>(); 54 | 55 | public SamlFileResourceCache(@NonNull String fileName) { 56 | LOG.log(Level.FINER, "Creating Resource cache: %s", fileName ); 57 | this.fileName = fileName; 58 | } 59 | 60 | public SamlFileResourceCache(@NonNull String fileName, @NonNull String data) { 61 | LOG.log(Level.FINER, "Creating Resource cache from data: %s", fileName ); 62 | this.fileName = fileName; 63 | try { 64 | save(fileName, data); 65 | } catch (UnsupportedEncodingException e) { 66 | throw new TechnicalException("Could not get string bytes.", e); 67 | } catch (java.io.IOException e) { 68 | throw new TechnicalException("Could not save the " + fileName + " file.", e); 69 | } 70 | } 71 | 72 | @Override 73 | public boolean exists() { 74 | return new File(fileName).exists(); 75 | } 76 | 77 | @Override 78 | public boolean isReadable() { 79 | return new File(fileName).canRead(); 80 | } 81 | 82 | @Override 83 | public boolean isOpen() { 84 | return false; 85 | } 86 | 87 | @Override 88 | public URL getURL() throws MalformedURLException { 89 | return getURI().toURL(); 90 | } 91 | 92 | @Override 93 | public URI getURI() { 94 | return getFile().toURI(); 95 | } 96 | 97 | @Override 98 | public String getFilename() { 99 | return fileName; 100 | } 101 | 102 | @Override 103 | public String getDescription() { 104 | return fileName; 105 | } 106 | 107 | @Override 108 | public InputStream getInputStream() throws IOException { 109 | LOG.log(Level.FINER, "Get cache inputStream : %s", fileName ); 110 | if (cache.containsKey(fileName)){ 111 | return IOUtils.toInputStream(cache.get(fileName),"UTF-8"); 112 | } else { 113 | return FileUtils.openInputStream(getFile()); 114 | } 115 | } 116 | 117 | @Override 118 | public File getFile() { 119 | return new File(fileName); 120 | } 121 | 122 | @Override 123 | public long contentLength() { 124 | return getFile().length(); 125 | } 126 | 127 | @Override 128 | public long lastModified() { 129 | return getFile().lastModified(); 130 | } 131 | 132 | @Override 133 | public Resource createRelative(String s) { 134 | throw new NotImplementedException(); 135 | } 136 | 137 | @Override 138 | public boolean isWritable() { 139 | return new File(fileName).canWrite(); 140 | } 141 | 142 | @Override 143 | public OutputStream getOutputStream() throws IOException { 144 | LOG.log(Level.FINER, "Creating cache outputStream: %s", fileName ); 145 | return new ByteArrayOutputStream(){ 146 | @Override 147 | public void close() throws IOException { 148 | save(fileName, IOUtils.toString(this.buf, "UTF-8").trim()); 149 | } 150 | }; 151 | } 152 | 153 | private boolean isNew(String fileName, String data){ 154 | String oldData = cache.containsKey(fileName) ? cache.get(fileName) : ""; 155 | String md5SumNew = org.apache.commons.codec.digest.DigestUtils.md5Hex(data); 156 | String md5SumOld = org.apache.commons.codec.digest.DigestUtils.md5Hex(oldData); 157 | return !md5SumNew.equals(md5SumOld); 158 | } 159 | 160 | private void save(@NonNull String fileName, @NonNull String data) throws IOException { 161 | if(isNew(fileName, data)) { 162 | LOG.log(Level.FINER, "Save resource to disk : %s", fileName ); 163 | Files.write(new File(fileName).toPath(), data.getBytes("UTF-8")); 164 | cache.put(fileName, data); 165 | } 166 | } 167 | } -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlFileResourceDisk.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import java.io.File; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.OutputStream; 24 | import java.io.UnsupportedEncodingException; 25 | import java.net.MalformedURLException; 26 | import java.net.URI; 27 | import java.net.URL; 28 | import java.nio.charset.StandardCharsets; 29 | import java.nio.file.Files; 30 | 31 | import org.apache.commons.io.FileUtils; 32 | import org.apache.commons.lang.NotImplementedException; 33 | import org.pac4j.core.exception.TechnicalException; 34 | import org.springframework.core.io.Resource; 35 | import org.springframework.core.io.WritableResource; 36 | 37 | import edu.umd.cs.findbugs.annotations.NonNull; 38 | 39 | /** 40 | * Class to manage the metadata files. 41 | */ 42 | class SamlFileResourceDisk implements WritableResource { 43 | 44 | private final String fileName; 45 | 46 | public SamlFileResourceDisk(@NonNull String fileName) { 47 | this.fileName = fileName; 48 | } 49 | 50 | public SamlFileResourceDisk(@NonNull String fileName, @NonNull String data) { 51 | this.fileName = fileName; 52 | try { 53 | Files.write(getFile().toPath(), data.getBytes(StandardCharsets.UTF_8)); 54 | } catch (UnsupportedEncodingException e) { 55 | throw new TechnicalException("Could not get string bytes.", e); 56 | } catch (java.io.IOException e) { 57 | throw new TechnicalException("Could not save the " + fileName + " file.", e); 58 | } 59 | } 60 | 61 | @Override 62 | public boolean exists() { 63 | return getFile().exists(); 64 | } 65 | 66 | @Override 67 | public boolean isReadable() { 68 | return getFile().canRead(); 69 | } 70 | 71 | @Override 72 | public boolean isOpen() { 73 | return false; 74 | } 75 | 76 | @NonNull 77 | @Override 78 | public URL getURL() throws MalformedURLException { 79 | return getURI().toURL(); 80 | } 81 | 82 | @NonNull 83 | @Override 84 | public URI getURI() { 85 | return getFile().toURI(); 86 | } 87 | 88 | @Override 89 | public String getFilename() { 90 | return fileName; 91 | } 92 | 93 | @NonNull 94 | @Override 95 | public String getDescription() { 96 | return fileName; 97 | } 98 | 99 | @NonNull 100 | @Override 101 | public InputStream getInputStream() throws IOException { 102 | return FileUtils.openInputStream(getFile()); 103 | } 104 | 105 | @NonNull 106 | @Override 107 | public File getFile() { 108 | return new File(fileName); 109 | } 110 | 111 | @Override 112 | public long contentLength() { 113 | return getFile().length(); 114 | } 115 | 116 | @Override 117 | public long lastModified() { 118 | return getFile().lastModified(); 119 | } 120 | 121 | @NonNull 122 | @Override 123 | public Resource createRelative(@NonNull String s) { 124 | throw new NotImplementedException(); 125 | } 126 | 127 | @Override 128 | public boolean isWritable() { 129 | return getFile().canWrite(); 130 | } 131 | 132 | @NonNull 133 | @Override 134 | public OutputStream getOutputStream() throws IOException { 135 | return Files.newOutputStream(getFile().toPath()); 136 | } 137 | } -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlFormValidation.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.saml; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | import jakarta.mail.internet.AddressException; 6 | import jakarta.mail.internet.InternetAddress; 7 | import org.apache.commons.lang.StringUtils; 8 | import org.kohsuke.accmod.Restricted; 9 | import org.kohsuke.accmod.restrictions.NoExternalUse; 10 | import hudson.util.FormValidation; 11 | import static org.jenkinsci.plugins.saml.SamlSecurityRealm.ERROR_NOT_VALID_NUMBER; 12 | import static org.jenkinsci.plugins.saml.SamlSecurityRealm.ERROR_ONLY_SPACES_FIELD_VALUE; 13 | 14 | @Restricted(NoExternalUse.class) 15 | class SamlFormValidation { 16 | 17 | private SamlFormValidation(){} 18 | 19 | public static FormValidation checkStringFormat(String value) { 20 | 21 | if (StringUtils.isEmpty(value)) { 22 | return FormValidation.ok(); 23 | } 24 | 25 | if (StringUtils.isBlank(value)) { 26 | return FormValidation.error(ERROR_ONLY_SPACES_FIELD_VALUE); 27 | } 28 | 29 | return FormValidation.ok(); 30 | 31 | } 32 | 33 | public static FormValidation checkStringAttributeFormat(String value, String message, boolean warn) { 34 | 35 | if (warn && StringUtils.isEmpty(value)) { 36 | return FormValidation.warning(message); 37 | } 38 | 39 | if (StringUtils.isBlank(value)) { 40 | return FormValidation.error(ERROR_ONLY_SPACES_FIELD_VALUE); 41 | } 42 | 43 | return FormValidation.ok(); 44 | 45 | } 46 | 47 | public static FormValidation checkEmailFormat(String value, String message) { 48 | 49 | try { 50 | if(!StringUtils.isEmpty(value)) { 51 | InternetAddress ia = new InternetAddress(value); 52 | ia.validate(); 53 | } 54 | else { 55 | return FormValidation.warning(message); 56 | } 57 | } 58 | catch (AddressException ae) { 59 | return FormValidation.error(message); 60 | } 61 | 62 | return FormValidation.ok(); 63 | 64 | } 65 | 66 | public static FormValidation checkUrlFormat(String url) { 67 | if (StringUtils.isEmpty(url)) { 68 | return FormValidation.ok(); 69 | } 70 | try { 71 | new URL(url); 72 | } catch (MalformedURLException e) { 73 | return FormValidation.error(SamlSecurityRealm.ERROR_MALFORMED_URL, e); 74 | } 75 | return FormValidation.ok(); 76 | } 77 | 78 | public static FormValidation checkIntegerFormat(String value) { 79 | if (StringUtils.isEmpty(value)) { 80 | return FormValidation.ok(); 81 | } 82 | 83 | long i = 0; 84 | try { 85 | i = Long.parseLong(value); 86 | } catch (NumberFormatException e) { 87 | return FormValidation.error(ERROR_NOT_VALID_NUMBER, e); 88 | } 89 | 90 | if (i < 0) { 91 | return FormValidation.error(ERROR_NOT_VALID_NUMBER); 92 | } 93 | 94 | if (i > Integer.MAX_VALUE) { 95 | return FormValidation.error(ERROR_NOT_VALID_NUMBER); 96 | } 97 | 98 | return FormValidation.ok(); 99 | } 100 | 101 | } -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlGroupDetails.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | package org.jenkinsci.plugins.saml; 18 | 19 | import java.util.HashSet; 20 | import java.util.Set; 21 | import hudson.model.User; 22 | import hudson.security.GroupDetails; 23 | import jenkins.security.LastGrantedAuthoritiesProperty; 24 | 25 | 26 | /** 27 | * Created by kuisathaverat on 03/05/2017. 28 | *

29 | * SAML Group details return the details of a group based on login details of users 30 | */ 31 | public class SamlGroupDetails extends GroupDetails { 32 | 33 | private final String name; 34 | private final Set members = new HashSet<>(); 35 | 36 | public SamlGroupDetails(String name) { 37 | this.name = name; 38 | } 39 | 40 | @Override 41 | public String getName() { 42 | return name; 43 | } 44 | 45 | @Override 46 | public String getDisplayName() { 47 | return getName(); 48 | } 49 | 50 | @Override 51 | public Set getMembers() { 52 | if (members.isEmpty()) { 53 | User.getAll().forEach(u -> { 54 | LastGrantedAuthoritiesProperty prop = u.getProperty(LastGrantedAuthoritiesProperty.class); 55 | if (hasGroupOnAuthorities(prop)) { 56 | members.add(u.getId()); 57 | } 58 | }); 59 | } 60 | return members; 61 | } 62 | 63 | private boolean hasGroupOnAuthorities(LastGrantedAuthoritiesProperty prop) { 64 | if (prop != null) { 65 | return prop.getAuthorities2().stream().anyMatch(a -> name.equals(a.getAuthority())); 66 | } 67 | return false; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlLogoutAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2016 CloudBees, Inc., James Nord 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.saml; 25 | 26 | import hudson.Extension; 27 | import hudson.model.UnprotectedRootAction; 28 | 29 | /** 30 | * A page that shows a simple message when the user logs out. 31 | * This prevents a logout - login loop when using this security realm and Anonymous does not have {@code Overall.READ} permission. 32 | */ 33 | @Extension 34 | public class SamlLogoutAction implements UnprotectedRootAction { 35 | 36 | /** 37 | * The URL of the action. 38 | */ 39 | static final String POST_LOGOUT_URL = "samlLogout"; 40 | 41 | @Override 42 | public String getDisplayName() { 43 | return "SAML Logout"; 44 | } 45 | 46 | @Override 47 | public String getIconFileName() { 48 | // hide it 49 | return null; 50 | } 51 | 52 | @Override 53 | public String getUrlName() { 54 | return POST_LOGOUT_URL; 55 | } 56 | } -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlPluginConfig.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import org.apache.commons.lang.StringUtils; 21 | import jenkins.model.Jenkins; 22 | import static org.jenkinsci.plugins.saml.SamlSecurityRealm.CONSUMER_SERVICE_URL_PATH; 23 | import static org.jenkinsci.plugins.saml.SamlSecurityRealm.DEFAULT_USERNAME_CASE_CONVERSION; 24 | 25 | /** 26 | * contains all the Jenkins SAML Plugin settings 27 | */ 28 | public class SamlPluginConfig { 29 | private final String displayNameAttributeName; 30 | private final String groupsAttributeName; 31 | private final int maximumAuthenticationLifetime; 32 | private final String emailAttributeName; 33 | 34 | private final IdpMetadataConfiguration idpMetadataConfiguration; 35 | private final String usernameCaseConversion; 36 | private final String usernameAttributeName; 37 | private final String logoutUrl; 38 | private final String binding; 39 | 40 | private final SamlEncryptionData encryptionData; 41 | private final SamlAdvancedConfiguration advancedConfiguration; 42 | 43 | public SamlPluginConfig(String displayNameAttributeName, String groupsAttributeName, 44 | int maximumAuthenticationLifetime, String emailAttributeName, IdpMetadataConfiguration idpMetadataConfiguration, 45 | String usernameCaseConversion, String usernameAttributeName, String logoutUrl, String binding, 46 | SamlEncryptionData encryptionData, SamlAdvancedConfiguration advancedConfiguration) { 47 | this.displayNameAttributeName = displayNameAttributeName; 48 | this.groupsAttributeName = groupsAttributeName; 49 | this.maximumAuthenticationLifetime = maximumAuthenticationLifetime; 50 | this.emailAttributeName = emailAttributeName; 51 | this.idpMetadataConfiguration = idpMetadataConfiguration; 52 | this.usernameCaseConversion = StringUtils.defaultIfBlank(usernameCaseConversion, DEFAULT_USERNAME_CASE_CONVERSION); 53 | this.usernameAttributeName = hudson.Util.fixEmptyAndTrim(usernameAttributeName); 54 | this.logoutUrl = logoutUrl; 55 | this.binding = binding; 56 | this.encryptionData = encryptionData; 57 | this.advancedConfiguration = advancedConfiguration; 58 | } 59 | 60 | public String getUsernameAttributeName() { 61 | return usernameAttributeName; 62 | } 63 | 64 | 65 | public String getDisplayNameAttributeName() { 66 | return displayNameAttributeName; 67 | } 68 | 69 | public String getGroupsAttributeName() { 70 | return groupsAttributeName; 71 | } 72 | 73 | public Integer getMaximumAuthenticationLifetime() { 74 | return maximumAuthenticationLifetime; 75 | } 76 | 77 | public SamlAdvancedConfiguration getAdvancedConfiguration() { 78 | return advancedConfiguration; 79 | } 80 | 81 | public Boolean getForceAuthn() { 82 | return getAdvancedConfiguration() != null ? getAdvancedConfiguration().getForceAuthn() : Boolean.FALSE; 83 | } 84 | 85 | public String getAuthnContextClassRef() { 86 | return getAdvancedConfiguration() != null ? getAdvancedConfiguration().getAuthnContextClassRef() : null; 87 | } 88 | 89 | public String getSpEntityId() { 90 | return getAdvancedConfiguration() != null ? getAdvancedConfiguration().getSpEntityId() : null; 91 | } 92 | 93 | public String getNameIdPolicyFormat() { 94 | return getAdvancedConfiguration() != null ? getAdvancedConfiguration().getNameIdPolicyFormat() : null; 95 | } 96 | 97 | public SamlEncryptionData getEncryptionData() { 98 | return encryptionData; 99 | } 100 | 101 | public String getUsernameCaseConversion() { 102 | return usernameCaseConversion; 103 | } 104 | 105 | public String getEmailAttributeName() { 106 | return emailAttributeName; 107 | } 108 | 109 | public String getLogoutUrl() { 110 | return logoutUrl; 111 | } 112 | 113 | public String getConsumerServiceUrl() { 114 | return baseUrl() + CONSUMER_SERVICE_URL_PATH; 115 | } 116 | 117 | public String baseUrl() { 118 | return Jenkins.get().getRootUrl(); 119 | } 120 | 121 | public IdpMetadataConfiguration getIdpMetadataConfiguration() { 122 | return idpMetadataConfiguration; 123 | } 124 | 125 | public String getBinding() { 126 | return binding; 127 | } 128 | 129 | @Override 130 | public String toString() { 131 | return "SamlPluginConfig{" + "idpMetadataConfiguration='" + getIdpMetadataConfiguration() + '\'' 132 | + ", displayNameAttributeName='" + getDisplayNameAttributeName() + '\'' + ", groupsAttributeName='" 133 | + getGroupsAttributeName() + '\'' + ", emailAttributeName='" + getEmailAttributeName() + '\'' 134 | + ", usernameAttributeName='" + getUsernameAttributeName() + '\'' 135 | + ", maximumAuthenticationLifetime=" + getMaximumAuthenticationLifetime() 136 | + ", usernameCaseConversion='" + getUsernameCaseConversion() + '\'' + ", logoutUrl='" 137 | + getLogoutUrl() + '\'' + ", binding='" + getBinding() + '\'' + ", encryptionData=" 138 | + getEncryptionData() + ", advancedConfiguration=" + getAdvancedConfiguration() + '}'; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlProfileWrapper.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import java.io.IOException; 21 | import java.util.logging.Logger; 22 | import org.kohsuke.stapler.StaplerRequest2; 23 | import org.kohsuke.stapler.StaplerResponse2; 24 | import org.pac4j.core.context.CallContext; 25 | import org.pac4j.core.context.WebContext; 26 | import org.pac4j.core.context.session.SessionStore; 27 | import org.pac4j.core.exception.http.HttpAction; 28 | import org.pac4j.saml.client.SAML2Client; 29 | import org.pac4j.saml.credentials.SAML2AuthenticationCredentials; 30 | import org.pac4j.saml.credentials.SAML2Credentials; 31 | import org.pac4j.saml.exceptions.SAMLException; 32 | import org.pac4j.saml.profile.SAML2Profile; 33 | import org.springframework.security.authentication.BadCredentialsException; 34 | 35 | /** 36 | * Process to response from the IdP to obtain the SAML2Profile of the user. 37 | */ 38 | public class SamlProfileWrapper extends OpenSAMLWrapper { 39 | private static final Logger LOG = Logger.getLogger(SamlProfileWrapper.class.getName()); 40 | 41 | 42 | public SamlProfileWrapper(SamlPluginConfig samlPluginConfig, StaplerRequest2 request, StaplerResponse2 response) { 43 | this.request = request; 44 | this.response = response; 45 | this.samlPluginConfig = samlPluginConfig; 46 | } 47 | 48 | /** 49 | * @return the SAML2Profile of the user returned by the IdP. 50 | */ 51 | @Override 52 | protected SAML2Profile process() { 53 | SAML2AuthenticationCredentials credentials; 54 | SAML2Profile saml2Profile; 55 | try (SAML2Client client = createSAML2Client()) { 56 | WebContext context = createWebContext(); 57 | SessionStore sessionStore = createSessionStore(); 58 | CallContext ctx = new CallContext(context, sessionStore); 59 | SAML2Credentials unvalidated = (SAML2Credentials) client.getCredentials(ctx).orElse(null); 60 | credentials = (SAML2AuthenticationCredentials) client.validateCredentials(ctx, unvalidated).orElse(null); 61 | saml2Profile = (SAML2Profile) client.getUserProfile(ctx, credentials).orElse(null); 62 | client.destroy(); 63 | } catch (HttpAction|SAMLException e) { 64 | //if the SAMLResponse is not valid we send the user again to the IdP 65 | throw new BadCredentialsException(e.getMessage(), e); 66 | } 67 | if (saml2Profile == null) { 68 | String msg = "Could not find user profile for SAML credentials: " + credentials; 69 | LOG.severe(msg); 70 | throw new BadCredentialsException(msg); 71 | } 72 | 73 | LOG.finer(saml2Profile.toString()); 74 | return saml2Profile; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlRedirectActionWrapper.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import java.io.IOException; 21 | 22 | import org.kohsuke.stapler.StaplerRequest2; 23 | import org.kohsuke.stapler.StaplerResponse2; 24 | import org.pac4j.core.context.CallContext; 25 | import org.pac4j.core.context.session.SessionStore; 26 | import org.pac4j.core.exception.http.HttpAction; 27 | import org.pac4j.core.exception.http.RedirectionAction; 28 | import org.pac4j.core.context.WebContext; 29 | import org.pac4j.saml.client.SAML2Client; 30 | 31 | /** 32 | * Process the current configuration and request to prepare a Redirection to the IdP. 33 | */ 34 | public class SamlRedirectActionWrapper extends OpenSAMLWrapper { 35 | 36 | public SamlRedirectActionWrapper(SamlPluginConfig samlPluginConfig, StaplerRequest2 request, StaplerResponse2 response) { 37 | this.request = request; 38 | this.response = response; 39 | this.samlPluginConfig = samlPluginConfig; 40 | } 41 | 42 | /** 43 | * @return the redirection URL to the IdP. 44 | * @throws IllegalStateException if something goes wrong. 45 | */ 46 | @Override 47 | protected RedirectionAction process() throws IllegalStateException { 48 | try (SAML2Client client = createSAML2Client()) { 49 | WebContext context = createWebContext(); 50 | SessionStore sessionStore = createSessionStore(); 51 | CallContext ctx = new CallContext(context, sessionStore); 52 | RedirectionAction redirection = client.getRedirectionAction(ctx).orElse(null); 53 | client.destroy(); 54 | return redirection; 55 | } catch (HttpAction e) { 56 | throw new IllegalStateException(e); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlSPMetadataWrapper.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import java.io.IOException; 21 | 22 | import org.kohsuke.stapler.HttpResponse; 23 | import org.kohsuke.stapler.HttpResponses; 24 | import org.kohsuke.stapler.StaplerRequest2; 25 | import org.kohsuke.stapler.StaplerResponse2; 26 | import org.pac4j.core.exception.TechnicalException; 27 | import org.pac4j.saml.client.SAML2Client; 28 | 29 | /** 30 | * build the Service Provider(SP) metadata from the configuration. 31 | */ 32 | public class SamlSPMetadataWrapper extends OpenSAMLWrapper { 33 | 34 | public SamlSPMetadataWrapper(SamlPluginConfig samlPluginConfig, StaplerRequest2 request, StaplerResponse2 response) { 35 | this.request = request; 36 | this.response = response; 37 | this.samlPluginConfig = samlPluginConfig; 38 | } 39 | 40 | /** 41 | * @return the metadata of the SP. 42 | * @throws IllegalStateException if something goes wrong. 43 | */ 44 | @Override 45 | protected HttpResponse process() throws IllegalStateException { 46 | String metadata = ""; 47 | try (SAML2Client client = createSAML2Client()) { 48 | metadata = client.getServiceProviderMetadataResolver().getMetadata(); 49 | client.destroy(); 50 | } catch (TechnicalException e) { 51 | throw new IllegalStateException(e); 52 | } 53 | return HttpResponses.text(metadata); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlUserDetails.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import java.util.Arrays; 21 | import java.util.Collection; 22 | import java.util.Collections; 23 | import edu.umd.cs.findbugs.annotations.NonNull; 24 | import java.util.Arrays; 25 | import java.util.Collections; 26 | import org.springframework.security.core.GrantedAuthority; 27 | import org.springframework.security.core.userdetails.UserDetails; 28 | 29 | /** 30 | * @see UserDetails 31 | */ 32 | public class SamlUserDetails implements UserDetails { 33 | 34 | private static final long serialVersionUID = 2L; 35 | 36 | private final String username; 37 | private final Collection authorities; 38 | 39 | public SamlUserDetails(@NonNull String username, Collection authorities) { 40 | this.username = username; 41 | this.authorities = Collections.unmodifiableCollection(authorities); 42 | } 43 | 44 | public Collection getAuthorities() { 45 | return authorities; 46 | } 47 | 48 | public String getPassword() { 49 | return null; 50 | } 51 | 52 | public String getUsername() { 53 | return username; 54 | } 55 | 56 | public boolean isAccountNonExpired() { 57 | return true; 58 | } 59 | 60 | public boolean isAccountNonLocked() { 61 | return true; 62 | } 63 | 64 | public boolean isCredentialsNonExpired() { 65 | return true; 66 | } 67 | 68 | public boolean isEnabled() { 69 | return true; 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return "SamlUserDetails{" + "username='" + getUsername() + '\'' + ", authorities=" + (getAuthorities() == null 75 | ? "null" 76 | : Arrays.asList(getAuthorities()).toString()) 77 | + '\'' + ", isAccountNonExpired='" + isAccountNonExpired() + '\'' + ", isAccountNonLocked='" 78 | + isAccountNonLocked() + '\'' + ", isCredentialsNonExpired='" + isCredentialsNonExpired() + '\'' 79 | + ", isEnabled='" + isEnabled() + '}'; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlUserDetailsService.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Collections; 22 | import java.util.List; 23 | import edu.umd.cs.findbugs.annotations.NonNull; 24 | import org.springframework.security.core.Authentication; 25 | import org.springframework.security.core.GrantedAuthority; 26 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 27 | import org.springframework.security.core.userdetails.UserDetailsService; 28 | import hudson.model.User; 29 | import hudson.security.SecurityRealm; 30 | import hudson.security.UserMayOrMayNotExistException2; 31 | import jenkins.model.Jenkins; 32 | import jenkins.security.LastGrantedAuthoritiesProperty; 33 | 34 | /** 35 | * This service is responsible for restoring UserDetails object by userId 36 | * 37 | * @see UserDetailsService 38 | */ 39 | public class SamlUserDetailsService implements UserDetailsService { 40 | 41 | public SamlUserDetails loadUserByUsername(@NonNull String username) { 42 | 43 | // try to obtain user details from current authentication details 44 | Authentication auth = Jenkins.getAuthentication2(); 45 | if (username.compareTo(auth.getName()) == 0 && auth instanceof SamlAuthenticationToken) { 46 | return (SamlUserDetails) auth.getDetails(); 47 | } 48 | 49 | // try to rebuild authentication details based on data stored in user storage 50 | User user = User.get(username, false, Collections.emptyMap()); 51 | if (user == null) { 52 | // User logged in to Jenkins, but it could exist in the backend 53 | throw new UserMayOrMayNotExistException2(username); 54 | } 55 | 56 | Listauthorities = new ArrayList<>(); 57 | authorities.add(SecurityRealm.AUTHENTICATED_AUTHORITY2); 58 | 59 | if (username.compareTo(user.getId()) == 0) { 60 | LastGrantedAuthoritiesProperty lastGranted = user.getProperty(LastGrantedAuthoritiesProperty.class); 61 | if (lastGranted != null) { 62 | for (GrantedAuthority a : lastGranted.getAuthorities2()) { 63 | if (a != SecurityRealm.AUTHENTICATED_AUTHORITY2) { 64 | SimpleGrantedAuthority ga = new SimpleGrantedAuthority(a.getAuthority()); 65 | authorities.add(ga); 66 | } 67 | } 68 | } 69 | } 70 | return new SamlUserDetails(user.getId(), authorities); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/SamlValidateIdPMetadata.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.saml; 2 | 3 | import java.io.IOException; 4 | import net.shibboleth.shared.component.ComponentInitializationException; 5 | import net.shibboleth.shared.xml.XMLParserException; 6 | import org.apache.commons.io.IOUtils; 7 | import org.opensaml.saml.metadata.resolver.impl.DOMMetadataResolver; 8 | import org.pac4j.saml.util.Configuration; 9 | import hudson.util.FormValidation; 10 | 11 | /** 12 | * validate the IdP metadata, this class is used from the configuration screen to validate the XML in the IdP Metadata textarea. 13 | */ 14 | public class SamlValidateIdPMetadata extends OpenSAMLWrapper{ 15 | 16 | private final String idpMetadata; 17 | 18 | public SamlValidateIdPMetadata(String idpMetadata){ 19 | this.idpMetadata = idpMetadata; 20 | } 21 | 22 | /** 23 | * process the IdP Metadata and try to parse it, if so, then return that the validation is ok. 24 | * @return ok if the IdP Metadata it right, if not return a validation error. 25 | */ 26 | @Override 27 | protected FormValidation process() { 28 | try (final java.io.InputStream in = IOUtils.toInputStream(idpMetadata, "UTF-8")) { 29 | final org.w3c.dom.Document inCommonMDDoc = Configuration.getParserPool().parse(in); 30 | final org.w3c.dom.Element metadataRoot = inCommonMDDoc.getDocumentElement(); 31 | DOMMetadataResolver idpMetadataProvider = new DOMMetadataResolver(metadataRoot); 32 | idpMetadataProvider.setParserPool(Configuration.getParserPool()); 33 | idpMetadataProvider.setFailFastInitialization(true); 34 | idpMetadataProvider.setRequireValidMetadata(true); 35 | idpMetadataProvider.setId(idpMetadataProvider.getClass().getCanonicalName()); 36 | idpMetadataProvider.initialize(); 37 | } catch (IOException e) { 38 | return FormValidation.error("The IdP Metadata not valid.", e); 39 | } catch (XMLParserException e) { 40 | return FormValidation.error("The IdP Metadata not valid XML.", e); 41 | } catch (ComponentInitializationException e) { 42 | return FormValidation.error("The IdP Metadata not valid content.", e); 43 | } 44 | return FormValidation.ok("Success"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/UpdateMetadataFromURLPeriodicWork.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.saml; 2 | 3 | import java.io.IOException; 4 | import java.util.concurrent.TimeUnit; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | import org.apache.commons.lang.StringUtils; 8 | import hudson.Extension; 9 | import hudson.model.AsyncAperiodicWork; 10 | import jenkins.model.Jenkins; 11 | 12 | /** 13 | *

This periodic work update the IdP Metadata File, the periodicof the execution is defined on the SAML Plugin configuration.

14 | *

If the Preriod is set to 0 the Periodic work is mostly disabled, it will check the changes on config 15 | * every 10 minutes to see if it is enabled again, if the period change it is re-enabled again.

16 | */ 17 | @Extension 18 | public class UpdateMetadataFromURLPeriodicWork extends AsyncAperiodicWork { 19 | private static final Logger LOG = Logger.getLogger(UpdateMetadataFromURLPeriodicWork.class.getName()); 20 | /** 21 | * property to set the initial delay of the AsyncAperiodicWork. 22 | * -Dorg.jenkinsci.plugins.saml.UpdateMetadataFromURLPeriodicWork.initialDelay=MILLISECONDS 23 | */ 24 | public static final String INITIAL_DELAY_PROPERTY = UpdateMetadataFromURLPeriodicWork.class.getName() + ".initialDelay"; 25 | public static final long INITIAL_DELAY = Long.parseLong(System.getProperty(INITIAL_DELAY_PROPERTY, "10000")); 26 | 27 | /** 28 | * {@inheritDoc} 29 | */ 30 | @SuppressWarnings("unused") 31 | public UpdateMetadataFromURLPeriodicWork() { 32 | super("Update IdP Metadata from URL PeriodicWork"); 33 | } 34 | 35 | /** 36 | * @return the configured period, if the configured period is 0 return 10 minutes, 37 | * if we are starting the Jenkins instance schedule an execution after 10 seconds. 38 | */ 39 | @Override 40 | public long getRecurrencePeriod() { 41 | long ret = getConfiguredPeriod(); 42 | if (ret == 0) { 43 | ret = TimeUnit.MINUTES.toMillis(10); 44 | } 45 | return ret; 46 | } 47 | 48 | /** 49 | * {@inheritDoc} 50 | */ 51 | @Override 52 | public long getInitialDelay() { 53 | return INITIAL_DELAY; 54 | } 55 | 56 | /** 57 | * @return check the configured period in the SAML Plugin configuration. 58 | */ 59 | private long getConfiguredPeriod() { 60 | long ret = 0; 61 | jenkins.model.Jenkins j = jenkins.model.Jenkins.get(); 62 | if (j.getSecurityRealm() instanceof SamlSecurityRealm) { 63 | SamlSecurityRealm samlSecurityRealm = (SamlSecurityRealm) j.getSecurityRealm(); 64 | IdpMetadataConfiguration config = samlSecurityRealm.getIdpMetadataConfiguration(); 65 | if(config != null && config.getPeriod() != null && StringUtils.isNotBlank(config.getUrl())) { 66 | ret = TimeUnit.MINUTES.toMillis(config.getPeriod()); 67 | } 68 | } 69 | return ret; 70 | } 71 | 72 | /** 73 | * {@inheritDoc} 74 | */ 75 | @Override 76 | public hudson.model.AperiodicWork getNewInstance() { 77 | return new UpdateMetadataFromURLPeriodicWork(); 78 | } 79 | 80 | /** 81 | * {@inheritDoc} 82 | *

Connect to the URL configured on the SAML configuration to get the IdP Metadata, then download it

83 | *

if the period configured is 0 it returns directly, do nothing.

84 | */ 85 | @Override 86 | protected void execute(hudson.model.TaskListener listener) { 87 | if (getConfiguredPeriod() == 0) { 88 | return; 89 | } 90 | 91 | Jenkins j = Jenkins.get(); 92 | if (j.getSecurityRealm() instanceof SamlSecurityRealm) { 93 | SamlSecurityRealm samlSecurityRealm = (SamlSecurityRealm) j.getSecurityRealm(); 94 | try { 95 | samlSecurityRealm.getIdpMetadataConfiguration().updateIdPMetadata(); 96 | } catch (IOException | IllegalArgumentException e) { 97 | LOG.log(Level.SEVERE, e.getMessage(), e); 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/conf/Attribute.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.saml.conf; 2 | 3 | import java.util.Objects; 4 | import edu.umd.cs.findbugs.annotations.NonNull; 5 | import org.kohsuke.stapler.DataBoundConstructor; 6 | import hudson.Extension; 7 | import hudson.model.Descriptor; 8 | 9 | /** 10 | * Class to configure SAML custom attributes to grab from the SAMLResponse and put in the User Profile. 11 | * 12 | * @author Kuisathaverat 13 | */ 14 | public class Attribute extends AttributeEntry { 15 | 16 | /** 17 | * Name of the attribute in the SAML Response. 18 | */ 19 | private final String name; 20 | /** 21 | * Name to display as attribute's value label on the user profile. 22 | */ 23 | private final String displayName; 24 | 25 | @SuppressWarnings("unused") 26 | @DataBoundConstructor 27 | public Attribute(String name, String displayName) { 28 | this.name = name; 29 | this.displayName = displayName; 30 | } 31 | 32 | public String getName() { 33 | return name; 34 | } 35 | 36 | public String getDisplayName() { 37 | return displayName; 38 | } 39 | 40 | @SuppressWarnings("unused") 41 | @Extension 42 | public static final class DescriptorImpl extends Descriptor { 43 | @NonNull 44 | @Override 45 | public String getDisplayName() { 46 | return "SAML Attribute"; 47 | } 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) return true; 53 | if (o == null || getClass() != o.getClass()) return false; 54 | Attribute attribute = (Attribute) o; 55 | return Objects.equals(name, attribute.name) && 56 | Objects.equals(displayName, attribute.displayName); 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return Objects.hash(name, displayName); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/conf/AttributeEntry.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.saml.conf; 2 | 3 | import hudson.model.AbstractDescribableImpl; 4 | 5 | /** 6 | * Parent Class for SAML Attributes configuration settings. 7 | * 8 | * @author Kuisathaverat 9 | */ 10 | public abstract class AttributeEntry extends AbstractDescribableImpl {} 11 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/user/LoginDetailsProperty.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | package org.jenkinsci.plugins.saml.user; 18 | 19 | import hudson.Extension; 20 | import hudson.model.Descriptor.FormException; 21 | import hudson.model.User; 22 | import hudson.model.UserProperty; 23 | import hudson.model.UserPropertyDescriptor; 24 | import edu.umd.cs.findbugs.annotations.NonNull; 25 | import net.sf.json.JSONObject; 26 | import org.apache.commons.lang.time.FastDateFormat; 27 | import hudson.security.SecurityRealm; 28 | import jenkins.model.Jenkins; 29 | import org.jenkinsci.plugins.saml.SamlSecurityRealm; 30 | import org.kohsuke.stapler.DataBoundConstructor; 31 | import org.kohsuke.stapler.StaplerRequest2; 32 | 33 | import java.util.Date; 34 | import java.util.logging.Level; 35 | import java.util.logging.Logger; 36 | import net.sf.json.JSONObject; 37 | import org.apache.commons.lang.time.FastDateFormat; 38 | import org.jenkinsci.plugins.saml.SamlSecurityRealm; 39 | import org.kohsuke.stapler.DataBoundConstructor; 40 | import org.kohsuke.stapler.StaplerRequest2; 41 | import org.springframework.security.core.Authentication; 42 | import hudson.Extension; 43 | import hudson.model.User; 44 | import hudson.model.UserProperty; 45 | import hudson.model.UserPropertyDescriptor; 46 | import hudson.security.SecurityRealm; 47 | import jenkins.model.Jenkins; 48 | 49 | /** 50 | * Store details about create and login processes 51 | * 52 | * @author Kuisathaverat 53 | */ 54 | public class LoginDetailsProperty extends UserProperty { 55 | private static final Logger LOG = Logger.getLogger(LoginDetailsProperty.class.getName()); 56 | private static final String ISO_8601 = "yyyy-MM-dd'T'HH:mm:ssZ"; 57 | private long createTimestamp; 58 | private long lastLoginTimestamp; 59 | private long loginCount; 60 | 61 | 62 | @SuppressWarnings("unused") 63 | @DataBoundConstructor 64 | public LoginDetailsProperty() { 65 | //NOOP 66 | } 67 | 68 | @SuppressWarnings("unused") 69 | public static LoginDetailsProperty currentUserLoginDetails() { 70 | User user = User.current(); 71 | LoginDetailsProperty loginDetails = null; 72 | if (user != null && user.getProperty(LoginDetailsProperty.class) != null) { 73 | loginDetails = user.getProperty(LoginDetailsProperty.class); 74 | } 75 | return loginDetails; 76 | } 77 | 78 | @SuppressWarnings("unused") 79 | public static void currentUserSetLoginDetails() { 80 | User user = User.current(); 81 | if (user != null && user.getProperty(LoginDetailsProperty.class) != null) { 82 | LoginDetailsProperty loginDetails = user.getProperty(LoginDetailsProperty.class); 83 | loginDetails.update(); 84 | } 85 | } 86 | 87 | public void update() { 88 | long now = System.currentTimeMillis(); 89 | if (getCreateTimestamp() == 0) { 90 | setCreateTimestamp(now); 91 | } 92 | 93 | setLastLoginTimestamp(now); 94 | setLoginCount(getLoginCount() + 1); 95 | try { 96 | user.save(); 97 | } catch (java.io.IOException e) { 98 | LOG.log(Level.WARNING, e.getMessage(), e); 99 | } 100 | } 101 | 102 | public long getCreateTimestamp() { 103 | return createTimestamp; 104 | } 105 | 106 | @SuppressWarnings("unused") 107 | public long getLastLoginTimestamp() { 108 | return lastLoginTimestamp; 109 | } 110 | 111 | @SuppressWarnings("unused") 112 | public String getCreateDate() { 113 | return FastDateFormat.getInstance(ISO_8601).format(new Date(createTimestamp)); 114 | } 115 | 116 | @SuppressWarnings("unused") 117 | public String getLastLoginDate() { 118 | return FastDateFormat.getInstance(ISO_8601).format(new Date(lastLoginTimestamp)); 119 | } 120 | 121 | public long getLoginCount() { 122 | return loginCount; 123 | } 124 | 125 | public void setCreateTimestamp(long createTimestamp) { 126 | this.createTimestamp = createTimestamp; 127 | } 128 | 129 | public void setLastLoginTimestamp(long lastLoginTimestamp) { 130 | this.lastLoginTimestamp = lastLoginTimestamp; 131 | } 132 | 133 | public void setLoginCount(long loginCount) { 134 | this.loginCount = loginCount; 135 | } 136 | 137 | @Override 138 | public UserProperty reconfigure(StaplerRequest2 req, JSONObject form) { 139 | return this; 140 | } 141 | 142 | 143 | /** 144 | * Listen to the login success/failure event to persist {@link LoginDetailsProperty}s properly. 145 | */ 146 | @SuppressWarnings("unused") 147 | @Extension 148 | public static class SecurityListenerImpl extends jenkins.security.SecurityListener { 149 | 150 | @Override 151 | protected void loggedIn(@edu.umd.cs.findbugs.annotations.NonNull String username) { 152 | 153 | SecurityRealm realm = Jenkins.get().getSecurityRealm(); 154 | if (!(realm instanceof SamlSecurityRealm)) { 155 | return; 156 | } 157 | 158 | 159 | try { 160 | User u = User.getById(username, true); 161 | LoginDetailsProperty o = u.getProperty(LoginDetailsProperty.class); 162 | if (o == null) { 163 | o = new LoginDetailsProperty(); 164 | } 165 | u.addProperty(o); 166 | Authentication a = Jenkins.getAuthentication2(); 167 | if (a.getName().equals(username)) { 168 | o.update(); // just for defensive sanity checking 169 | } 170 | } catch (java.io.IOException e) { 171 | LOG.log(Level.WARNING, "Failed to record granted authorities", e); 172 | } 173 | } 174 | 175 | } 176 | 177 | 178 | @SuppressWarnings("unused") 179 | @Extension 180 | public static final class DescriptorImpl extends UserPropertyDescriptor { 181 | @NonNull 182 | @Override 183 | public String getDisplayName() { 184 | return "User Login Properties"; 185 | } 186 | 187 | public LoginDetailsProperty newInstance(User user) { 188 | return new LoginDetailsProperty(); 189 | } 190 | 191 | @Override 192 | public boolean isEnabled() { 193 | return Jenkins.get().getSecurityRealm() instanceof SamlSecurityRealm; 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/saml/user/SamlCustomProperty.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | package org.jenkinsci.plugins.saml.user; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.Objects; 22 | import edu.umd.cs.findbugs.annotations.NonNull; 23 | import net.sf.json.JSONObject; 24 | import org.jenkinsci.plugins.saml.SamlSecurityRealm; 25 | import org.kohsuke.stapler.DataBoundConstructor; 26 | import org.kohsuke.stapler.StaplerRequest2; 27 | import hudson.Extension; 28 | import hudson.model.AbstractDescribableImpl; 29 | import hudson.model.Descriptor; 30 | import hudson.model.User; 31 | import hudson.model.UserProperty; 32 | import hudson.model.UserPropertyDescriptor; 33 | import jenkins.model.Jenkins; 34 | 35 | /** 36 | * Store custom SAMl Attributes read from SAML Response. 37 | * 38 | * @author Kuisathaverat 39 | */ 40 | public class SamlCustomProperty extends UserProperty { 41 | /** 42 | * list of custom Attributes. 43 | */ 44 | List attributes; 45 | 46 | public static class Attribute extends AbstractDescribableImpl { 47 | 48 | /** 49 | * Name of the attribute in the SAML Response. 50 | */ 51 | private final String name; 52 | /** 53 | * Name to display as attribute's value label on the user profile. 54 | */ 55 | private final String displayName; 56 | /** 57 | * value of the attribute. 58 | */ 59 | private String value; 60 | 61 | public Attribute(String name, String displayName) { 62 | this.name = name; 63 | this.displayName = displayName; 64 | } 65 | 66 | @SuppressWarnings("unused") 67 | public String getName() { 68 | return name; 69 | } 70 | 71 | @SuppressWarnings("unused") 72 | public String getDisplayName() { 73 | return displayName; 74 | } 75 | 76 | @SuppressWarnings("unused") 77 | public String getValue() { 78 | return value; 79 | } 80 | 81 | public void setValue(String value) { 82 | this.value = value; 83 | } 84 | 85 | @Override 86 | public boolean equals(Object o) { 87 | if (this == o) return true; 88 | if (o == null || getClass() != o.getClass()) return false; 89 | Attribute attribute = (Attribute) o; 90 | return Objects.equals(name, attribute.name) && 91 | Objects.equals(displayName, attribute.displayName) && 92 | Objects.equals(value, attribute.value); 93 | } 94 | 95 | @Override 96 | public int hashCode() { 97 | 98 | return Objects.hash(name, displayName, value); 99 | } 100 | 101 | @SuppressWarnings("unused") 102 | @Extension 103 | public static final class DescriptorImpl extends Descriptor { 104 | @NonNull 105 | @Override 106 | public String getDisplayName() { 107 | return "SAML Attribute"; 108 | } 109 | } 110 | 111 | } 112 | 113 | @DataBoundConstructor 114 | public SamlCustomProperty(List attributes) { 115 | this.attributes = attributes; 116 | } 117 | 118 | @NonNull 119 | public List getAttributes(){ 120 | if(attributes == null){ 121 | return java.util.Collections.emptyList(); 122 | } 123 | return attributes; 124 | } 125 | 126 | @SuppressWarnings("unused") 127 | public void setAttributes(List attributes) { 128 | this.attributes = attributes; 129 | } 130 | 131 | @Override 132 | public UserProperty reconfigure(StaplerRequest2 req, JSONObject form) { 133 | return this; 134 | } 135 | 136 | @SuppressWarnings("unused") 137 | @Extension 138 | public static final class DescriptorImpl extends UserPropertyDescriptor { 139 | @NonNull 140 | public String getDisplayName() { 141 | return "Saml Custom Attributes property"; 142 | } 143 | 144 | public SamlCustomProperty newInstance(User user) { 145 | return new SamlCustomProperty(new ArrayList<>()); 146 | } 147 | 148 | @Override 149 | public boolean isEnabled() { 150 | return Jenkins.get().getSecurityRealm() instanceof SamlSecurityRealm; 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | This plugin enables use of a SAML 2.0 authentication source for single sign-on support. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/src/main/resources/log4j.properties -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/IdpMetadataConfiguration/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 14 | 15 | 16 | 18 | 19 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/IdpMetadataConfiguration/help-period.html: -------------------------------------------------------------------------------- 1 |
2 | The period of minutes we will wait until refresh the IdP Metadata. Set it to 0 to not update the metadata. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/IdpMetadataConfiguration/help-url.html: -------------------------------------------------------------------------------- 1 |
2 | The Identity Provider metadata file source URL. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/IdpMetadataConfiguration/help-xml.html: -------------------------------------------------------------------------------- 1 |
2 | The Identity Provider metadata file content. 3 | see SAML metadata 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlAdvancedConfiguration/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlAdvancedConfiguration/help-authnContextClassRef.html: -------------------------------------------------------------------------------- 1 |
2 | If this field is not empty, request that the SAML IdP uses a specific 3 | authentication context, rather than its default. Check with the IdP 4 | administrators to find out which authentication contexts are available. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlAdvancedConfiguration/help-forceAuthn.html: -------------------------------------------------------------------------------- 1 |
2 | Whether to request the SAML IdP to force (re)authentication of the user, rather than allowing an existing session with the IdP to be reused. Off by default. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlAdvancedConfiguration/help-nameIdPolicyFormat.html: -------------------------------------------------------------------------------- 1 |
2 | Set your NameIDPolicy in the AuthnRequest, for example: urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlAdvancedConfiguration/help-randomRelayState.html: -------------------------------------------------------------------------------- 1 |
2 | When you enable this option the value of the relayState parameter sent to the IdP is a random generated value. 3 | The default value of relayState is JENKINS_URL/securityRealm/finishLogin 4 |
-------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlAdvancedConfiguration/help-spEntityId.html: -------------------------------------------------------------------------------- 1 |
2 | If this field is not empty, it overrides the default Entity ID for this Service Provider. 3 | Service Provider Entity IDs are usually a URL, like http://jenkins.example.org/. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlAdvancedConfiguration/help-useDiskCache.html: -------------------------------------------------------------------------------- 1 |
2 | The SP metadata is written on every login, 3 | enable this setting change the behaviour to use cache, 4 | and save the file only if it has changes. 5 |
-------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlEncryptionData/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlEncryptionData/help-forceSignRedirectBindingAuthnRequest.html: -------------------------------------------------------------------------------- 1 |
2 | Enable signature of the Auth Request. If you enable it the encryption and signing key would available in the SP metadata file and URL (JENKINS_URL/securityRealm/metadata). 3 | Disable signing auth request does not work with HTTP redirection binging, it only works for POST binding. 4 |
5 |         <md:SPSSODescriptor AuthnRequestsSigned="true" ...>
6 |     
7 |
-------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlEncryptionData/help-keyPassword.html: -------------------------------------------------------------------------------- 1 |
2 | The password used in the -keypass argument of keytool. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlEncryptionData/help-keystoreAlias.html: -------------------------------------------------------------------------------- 1 |
2 | The alias used in the -alias argument of the keytool command. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlEncryptionData/help-keystorePassword.html: -------------------------------------------------------------------------------- 1 |
2 | The password used in the -storepass argument of the keytool command. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlEncryptionData/help-keystorePath.html: -------------------------------------------------------------------------------- 1 |
2 | The path to the keystore file created with the keygen command. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlEncryptionData/help-wantsAssertionsSigned.html: -------------------------------------------------------------------------------- 1 |
2 | It requests signed assertions send by the IdP. 3 | The WantAssertionsSigned attribute on the <md:SPSSODescriptor> element declares 4 | that the service provider wants the <saml:Assertion> element to be digitally signed 5 | This attribute causes a metadata-aware identity provider to auto-configure itself at run time. 6 |
 7 |         <md:SPSSODescriptor WantAssertionsSigned="true" ...>
 8 |     
9 |
10 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlLogoutAction/index.jelly: -------------------------------------------------------------------------------- 1 | 19 | 20 | 22 | 23 | 24 | 25 | 26 |

You are now logged out of Jenkins, however this has not logged you out of SAML.

27 |

Have a nice day

28 |
29 | 30 |

Woo There....

31 |

You are not logged out - don't run away!

32 |

Whilst you should be logged out you are not actually logged out...

33 |
34 |
35 |
36 |
37 |
-------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 25 | 26 | 27 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | Service Provider Metadata 46 | which may be required to configure your Identity Provider 47 | (based on last saved settings). 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/help-advancedConfiguration.html: -------------------------------------------------------------------------------- 1 |
2 | You could enable this options to use SAML ForceAuthn to force logins at our IdP, 3 | AuthnContextClassRef to override the default authentication mechanism, 4 | and force multi-factor authentication; 5 | you also could set the sessions on Jenkins to be shorter than those on your IdP. 6 |
-------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/help-binding.html: -------------------------------------------------------------------------------- 1 |
2 | SAML Plugin supports two method of redirection binding HTTP-Redirect and HTTP-POST, by default HTTP-Redirect is used. 3 | Check supported binding redirection types of your IdP. 4 |
    5 |
  • HTTP-Redirect - urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
  • 6 |
  • HTTP-POST - urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect
  • 7 |
8 |
-------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/help-displayNameAttributeName.html: -------------------------------------------------------------------------------- 1 |
2 | Fill name of display name attribute in SAML response, default is http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/help-emailAttributeName.html: -------------------------------------------------------------------------------- 1 |
2 | Fill name of email attribute in SAML response. 3 |
-------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/help-encryptionData.html: -------------------------------------------------------------------------------- 1 |
2 | The SAML standard allows using a key-pair to authenticate and encrypt messages between 3 | service providers and identity providers.The IdP Metadata entered above contains the 4 | IdP's public key, and in order to use encryption for the messages passed from IdP to SP, 5 | you need to generate a key and enter the details here. Your IdP may or may not require 6 | or implement this encryption - check with the IdP administrator if unsure. 7 |

8 | The key can be created using the following command: 9 |

10 | $JAVA_HOME/bin/keytool -genkeypair -alias saml-key -keypass <pw1> \
11 |   -keystore /path/to/saml-key.jks -storepass  <pw2> \
12 |   -keyalg RSA -keysize 2048 -validity 3650
13 |   
14 | 
15 | where pw1 and pw2 are the key and store passwords respectively. These passwords need to be entered in the corresponding fields 16 | below. The validity period given above is 10 years, feel free to choose whatever period suits you. 17 |
18 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/help-groupsAttributeName.html: -------------------------------------------------------------------------------- 1 |
2 | Fill name of groups attribute in SAML response, default is http://schemas.xmlsoap.org/claims/Group 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/help-logoutUrl.html: -------------------------------------------------------------------------------- 1 |
2 | The url of your Identity Provider where you want to be redirected once logout. 3 |
-------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/help-maximumAuthenticationLifetime.html: -------------------------------------------------------------------------------- 1 |
2 | Number of seconds since user was authenticated in IdP while his authentication is considering as active. 3 | If you often get "No valid subject assertion found in response" or "Authentication issue instant is too old or in the future" 4 | then most probably you need to increase this value. 5 |
6 | Default is 24h * 60 min * 60 sec = 86400 7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/help-samlCustomAttributes.html: -------------------------------------------------------------------------------- 1 |
2 | You can define custom attributes to add to the User Profile from your SAML Response. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/help-usernameAttributeName.html: -------------------------------------------------------------------------------- 1 |
2 | The SAML attribute to use as the username. 3 | If blank, we use the nameid provided by the Identity Provider. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/SamlSecurityRealm/help-usernameCaseConversion.html: -------------------------------------------------------------------------------- 1 |
2 | The ID returned from SAML is used as the username for Authorization, which 3 | is usually case-sensitive. To make it easier to match with user definition 4 | in the policy, the returned value can be converted. 5 |
    6 |
  • None - will not change return value
  • 7 |
  • Lowercase - convert to lowercase
  • 8 |
  • Uppercase - convert to uppercase
  • 9 |
10 | Caution! Be aware of case in Authorization strategy as you 11 | may lose access rights if they do no match. 12 |
13 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/conf/Attribute/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/user/LoginDetailsProperty/config.jelly: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 |

Creation date: ${instance.createDate}

23 |

Last login: ${instance.lastLoginDate}

24 |

Login Count: ${instance.loginCount}

25 |
26 |
27 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/saml/user/SamlCustomProperty/config.jelly: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |

${displayName} : ${value}

27 |
28 |
29 |
30 | -------------------------------------------------------------------------------- /src/main/resources/samlKeystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/src/main/resources/samlKeystore.jks -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/saml/OpenSamlWrapperTest.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | 18 | package org.jenkinsci.plugins.saml; 19 | 20 | import hudson.util.Secret; 21 | import jakarta.servlet.ServletException; 22 | import org.apache.commons.io.IOUtils; 23 | import org.junit.jupiter.api.Test; 24 | import org.jvnet.hudson.test.JenkinsRule; 25 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 26 | import org.kohsuke.stapler.HttpResponse; 27 | import org.kohsuke.stapler.StaplerResponse2; 28 | import org.mockito.Mockito; 29 | 30 | import java.io.IOException; 31 | import java.io.PrintWriter; 32 | import java.io.StringWriter; 33 | import java.nio.charset.StandardCharsets; 34 | import java.util.Objects; 35 | 36 | import static org.hamcrest.MatcherAssert.assertThat; 37 | import static org.hamcrest.core.StringContains.containsString; 38 | import static org.mockito.Mockito.when; 39 | import static org.opensaml.saml.common.xml.SAMLConstants.SAML2_REDIRECT_BINDING_URI; 40 | 41 | /** 42 | * Different OpenSAMLWrapper classes tests 43 | */ 44 | @WithJenkins 45 | class OpenSamlWrapperTest { 46 | 47 | @Test 48 | void metadataWrapper(JenkinsRule jenkinsRule) throws IOException, ServletException { 49 | String metadata = IOUtils.toString( 50 | Objects.requireNonNull(this.getClass().getClassLoader().getResourceAsStream( 51 | "org/jenkinsci" + "/plugins/saml" + "/OpenSamlWrapperTest/metadataWrapper/metadata.xml")), 52 | StandardCharsets.UTF_8); 53 | SamlSecurityRealm samlSecurity = new SamlSecurityRealm(new IdpMetadataConfiguration(metadata), 54 | "displayName", "groups", 10000, 55 | "uid", "email", "/logout", null, 56 | null, "none", SAML2_REDIRECT_BINDING_URI, 57 | java.util.Collections.emptyList()); 58 | jenkinsRule.jenkins.setSecurityRealm(samlSecurity); 59 | SamlSPMetadataWrapper samlSPMetadataWrapper = new SamlSPMetadataWrapper(samlSecurity.getSamlPluginConfig(), null, null); 60 | HttpResponse process = samlSPMetadataWrapper.get(); 61 | StaplerResponse2 mockResponse = Mockito.mock(StaplerResponse2.class); 62 | StringWriter stringWriter = new StringWriter(); 63 | when(mockResponse.getWriter()).thenReturn(new PrintWriter(stringWriter)); 64 | process.generateResponse(null, mockResponse, null); 65 | String result = stringWriter.toString(); 66 | // Some random checks as the full XML comparison fails because of reformatting on processing 67 | assertThat(result, containsString("EntityDescriptor")); 68 | assertThat(result, containsString("urn:oasis:names:tc:SAML:2.0:nameid-format:transient")); 69 | assertThat(result, containsString("urn:oasis:names:tc:SAML:2.0:nameid-format:transient")); 98 | assertThat(result, containsString("")); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/saml/SamlCrumbExclusionTest.java: -------------------------------------------------------------------------------- 1 | /* Licensed to Jenkins CI under one or more contributor license 2 | agreements. See the NOTICE file distributed with this work 3 | for additional information regarding copyright ownership. 4 | Jenkins CI licenses this file to you under the Apache License, 5 | Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. */ 17 | package org.jenkinsci.plugins.saml; 18 | 19 | import jakarta.servlet.FilterChain; 20 | import jakarta.servlet.ServletException; 21 | import jakarta.servlet.http.HttpServletRequest; 22 | import jakarta.servlet.http.HttpServletResponse; 23 | import org.junit.jupiter.api.BeforeEach; 24 | import org.junit.jupiter.api.Test; 25 | import org.jvnet.hudson.test.JenkinsRule; 26 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 27 | import org.jvnet.hudson.test.recipes.LocalData; 28 | 29 | import java.io.IOException; 30 | 31 | import static org.junit.jupiter.api.Assertions.assertFalse; 32 | import static org.junit.jupiter.api.Assertions.assertTrue; 33 | 34 | /** 35 | * Test the ScrumExclusion. 36 | * 37 | * @author Ivan Fernandez Calvo 38 | */ 39 | @WithJenkins 40 | class SamlCrumbExclusionTest { 41 | 42 | private HttpServletRequest requestOK; 43 | private HttpServletRequest requestError; 44 | private HttpServletResponse response; 45 | private FilterChain filterChain; 46 | 47 | @BeforeEach 48 | void setup() { 49 | requestOK = new FakeRequest("/securityRealm/finishLogin"); 50 | requestError = new FakeRequest("/foo/securityRealm/finishLogin"); 51 | response = null; 52 | filterChain = (servletRequest, servletResponse) -> { 53 | }; 54 | } 55 | 56 | @LocalData("testReadSimpleConfiguration") 57 | @Test 58 | void testURL(JenkinsRule jenkinsRule) throws ServletException, IOException { 59 | SamlCrumbExclusion exclusion = new SamlCrumbExclusion(); 60 | assertTrue(exclusion.process(requestOK, response, filterChain)); 61 | assertFalse(exclusion.process(requestError, response, filterChain)); 62 | } 63 | 64 | @Test 65 | void testRealmDisabled(JenkinsRule jenkinsRule) throws ServletException, IOException { 66 | SamlCrumbExclusion exclusion = new SamlCrumbExclusion(); 67 | assertFalse(exclusion.process(requestOK, response, filterChain)); 68 | assertFalse(exclusion.process(requestError, response, filterChain)); 69 | } 70 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/saml/SamlFileResourceTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.saml; 2 | 3 | import hudson.security.SecurityRealm; 4 | import org.apache.commons.io.FileUtils; 5 | import org.apache.commons.io.IOUtils; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.jupiter.api.io.TempDir; 9 | import org.jvnet.hudson.test.JenkinsRule; 10 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 11 | import org.jvnet.hudson.test.recipes.LocalData; 12 | 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.io.OutputStream; 16 | import java.util.logging.Level; 17 | import java.util.logging.LogManager; 18 | import java.util.logging.Logger; 19 | 20 | import static java.nio.charset.StandardCharsets.UTF_8; 21 | import static org.hamcrest.MatcherAssert.assertThat; 22 | import static org.hamcrest.Matchers.instanceOf; 23 | import static org.junit.jupiter.api.Assertions.assertEquals; 24 | import static org.junit.jupiter.api.Assertions.assertNotEquals; 25 | 26 | /** 27 | * Test SamlFileResource implementations with and without cache. 28 | */ 29 | @WithJenkins 30 | class SamlFileResourceTest { 31 | 32 | @TempDir 33 | private File tempFolder; 34 | 35 | private SamlSecurityRealm samlSecurityRealm; 36 | 37 | @BeforeEach 38 | void start(JenkinsRule jenkinsRule) { 39 | SecurityRealm securityRealm = jenkinsRule.getInstance().getSecurityRealm(); 40 | assertThat("The security realm should be saml", securityRealm, instanceOf(SamlSecurityRealm.class)); 41 | samlSecurityRealm = (SamlSecurityRealm) securityRealm; 42 | Logger logger = Logger.getLogger("org.jenkinsci.plugins.saml"); 43 | logger.setLevel(Level.FINEST); 44 | LogManager.getLogManager().addLogger(logger); 45 | Logger logger1 = Logger.getLogger("org.pac4j"); 46 | logger1.setLevel(Level.FINEST); 47 | LogManager.getLogManager().addLogger(logger1); 48 | } 49 | 50 | @Test 51 | @LocalData("configuration") 52 | void testSamlFileResource() throws InterruptedException, IOException { 53 | samlSecurityRealm.getAdvancedConfiguration().setUseDiskCache(true); 54 | File tempFile = File.createTempFile("testSamlFileResource.txt", null, tempFolder); 55 | SamlFileResource obj = new SamlFileResource(tempFile.getAbsolutePath(), "data"); 56 | long timestamp = obj.lastModified(); 57 | 58 | Thread.sleep(1000); 59 | SamlFileResource obj1 = new SamlFileResource(tempFile.getAbsolutePath(), "data"); 60 | assertEquals(timestamp, obj1.lastModified()); 61 | 62 | SamlFileResource obj2 = new SamlFileResource(tempFile.getAbsolutePath(), "data1"); 63 | assertNotEquals(timestamp, obj2.lastModified()); 64 | } 65 | 66 | @Test 67 | @LocalData("configuration") 68 | void testGetInputStream() throws IOException { 69 | assertReadFile(); 70 | 71 | samlSecurityRealm.getAdvancedConfiguration().setUseDiskCache(true); 72 | assertReadFile(); 73 | } 74 | 75 | private void assertReadFile() throws IOException { 76 | File tempFile = getTempFile("testGetInputStream"); 77 | SamlFileResource obj = new SamlFileResource(tempFile.getAbsolutePath()); 78 | assertEquals("", IOUtils.toString(obj.getInputStream(), UTF_8)); 79 | assertEquals("", FileUtils.readFileToString(tempFile, UTF_8)); 80 | 81 | FileUtils.write(new File(tempFile.getAbsolutePath()), "data", UTF_8); 82 | assertEquals("data", IOUtils.toString(obj.getInputStream(), UTF_8)); 83 | assertEquals("data", FileUtils.readFileToString(tempFile, UTF_8)); 84 | 85 | SamlFileResource obj1 = new SamlFileResource(tempFile.getAbsolutePath(), "data1"); 86 | assertEquals("data1", IOUtils.toString(obj1.getInputStream(), UTF_8)); 87 | assertEquals("data1", FileUtils.readFileToString(tempFile, UTF_8)); 88 | } 89 | 90 | private File getTempFile(String filePattern) throws IOException { 91 | String type; 92 | if (samlSecurityRealm.getAdvancedConfiguration().getUseDiskCache()) { 93 | type = "_cache"; 94 | } else { 95 | type = "_file"; 96 | } 97 | return File.createTempFile(filePattern + type + ".txt", null, tempFolder); 98 | } 99 | 100 | @Test 101 | @LocalData("configuration") 102 | void testGetOutputStream() throws IOException { 103 | assertOutputStream(); 104 | 105 | samlSecurityRealm.getAdvancedConfiguration().setUseDiskCache(true); 106 | assertOutputStream(); 107 | } 108 | 109 | private void assertOutputStream() throws IOException { 110 | File tempFile = getTempFile("testGetOutputStream"); 111 | SamlFileResource obj = new SamlFileResource(tempFile.getAbsolutePath()); 112 | 113 | try (OutputStream out = obj.getOutputStream()) { 114 | IOUtils.write("data", out, UTF_8); 115 | } 116 | assertEquals("data", IOUtils.toString(obj.getInputStream(), UTF_8)); 117 | assertEquals("data", FileUtils.readFileToString(tempFile, UTF_8)); 118 | } 119 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/saml/SamlJCasCCompatibilityTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.saml; 2 | 3 | import hudson.security.SecurityRealm; 4 | import io.jenkins.plugins.casc.misc.junit.jupiter.AbstractRoundTripTest; 5 | import org.jenkinsci.plugins.saml.conf.Attribute; 6 | import org.jenkinsci.plugins.saml.conf.AttributeEntry; 7 | import org.jvnet.hudson.test.JenkinsRule; 8 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 9 | 10 | import java.util.List; 11 | 12 | import static org.hamcrest.CoreMatchers.containsString; 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | import static org.junit.jupiter.api.Assertions.assertEquals; 15 | import static org.junit.jupiter.api.Assertions.assertInstanceOf; 16 | import static org.junit.jupiter.api.Assertions.assertNotNull; 17 | import static org.junit.jupiter.api.Assertions.assertTrue; 18 | 19 | 20 | @WithJenkins 21 | class SamlJCasCCompatibilityTest extends AbstractRoundTripTest { 22 | 23 | @Override 24 | protected void assertConfiguredAsExpected(JenkinsRule jenkinsRule, String s) { 25 | final SecurityRealm realm = jenkinsRule.jenkins.getSecurityRealm(); 26 | assertNotNull(realm); 27 | assertInstanceOf(SamlSecurityRealm.class, realm); 28 | 29 | final SamlSecurityRealm samlRealm = (SamlSecurityRealm) realm; 30 | // Simple attributes 31 | assertEquals("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", samlRealm.getDisplayNameAttributeName()); 32 | assertEquals("http://schemas.xmlsoap.org/claims/Group", samlRealm.getGroupsAttributeName()); 33 | assertEquals(86400, samlRealm.getMaximumAuthenticationLifetime().longValue()); 34 | assertEquals("fake@mail.com", samlRealm.getEmailAttributeName()); 35 | assertEquals("urn:mace:dir:attribute-def:uid", samlRealm.getUsernameAttributeName()); 36 | assertEquals("none", samlRealm.getUsernameCaseConversion()); 37 | assertEquals("http://fake.logout.url", samlRealm.getLogoutUrl()); 38 | assertEquals("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", samlRealm.getBinding()); 39 | 40 | // Complex attributes 41 | final SamlAdvancedConfiguration advanced = samlRealm.getAdvancedConfiguration(); 42 | assertNotNull(advanced); 43 | assertTrue(advanced.getForceAuthn()); 44 | assertEquals("anotherContext", advanced.getAuthnContextClassRef()); 45 | assertEquals("mySpEntityId", advanced.getSpEntityId()); 46 | 47 | final SamlEncryptionData encryption = samlRealm.getEncryptionData(); 48 | assertNotNull(encryption); 49 | assertEquals("/home/jdk/keystore", encryption.getKeystorePath()); 50 | assertEquals("privatealias", encryption.getPrivateKeyAlias()); 51 | 52 | final IdpMetadataConfiguration metadata = samlRealm.getIdpMetadataConfiguration(); 53 | assertNotNull(metadata); 54 | assertEquals("http://fake.ldP.metadata.url", metadata.getUrl()); 55 | assertEquals(2, metadata.getPeriod().longValue()); 56 | assertThat(metadata.getXml(), containsString("")); 57 | assertThat(metadata.getXml(), containsString("")); 58 | assertThat(metadata.getXml(), containsString("Administrator")); 59 | assertThat(metadata.getXml(), containsString("dublindev@glgroup.com")); 60 | 61 | final List customAttributes = samlRealm.getSamlCustomAttributes(); 62 | assertNotNull(customAttributes); 63 | assertEquals(2, customAttributes.size()); 64 | assertEquals("attribute1", ((Attribute) customAttributes.get(0)).getName()); 65 | assertEquals("display1", ((Attribute) customAttributes.get(0)).getDisplayName()); 66 | assertEquals("attribute2", ((Attribute) customAttributes.get(1)).getName()); 67 | assertEquals("display2", ((Attribute) customAttributes.get(1)).getDisplayName()); 68 | } 69 | 70 | @Override 71 | protected String stringInLogExpected() { 72 | return "Setting class org.jenkinsci.plugins.saml.SamlSecurityRealm.emailAttributeName = fake@mail.com"; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/LiveTest/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | saml: 4 | image: "kristophjunge/test-saml-idp:1.14.15" 5 | environment: 6 | SIMPLESAMLPHP_SP_ENTITY_ID: "http://localhost:8080/jenkins/securityRealm/finishLogin" 7 | SIMPLESAMLPHP_SP_ASSERTION_CONSUMER_SERVICE: "http://localhost:8080/jenkins/securityRealm/finishLogin" 8 | SIMPLESAMLPHP_SP_SINGLE_LOGOUT_SERVICE: "http://localhost:8080/jenkins/logout" 9 | SIMPLESAMLPHP_ADMIN_PASSWORD: "admin" 10 | ports: 11 | - "58080:80" 12 | volumes: 13 | - "./config.php:/var/www/simplesamlphp/config/config.ph" 14 | - "./users.php:/var/www/simplesamlphp/config/authsources.php" 15 | - "./saml20-idp-hosted.php:/var/www/simplesamlphp/metadata/saml20-idp-hosted.php" 16 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/LiveTest/saml-key.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/src/test/resources/org/jenkinsci/plugins/saml/LiveTest/saml-key.jks -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/LiveTest/saml20-idp-hosted.php: -------------------------------------------------------------------------------- 1 | '__DEFAULT__', 15 | 16 | /* X.509 key and certificate. Relative to the cert directory. */ 17 | 'privatekey' => 'server.pem', 18 | 'certificate' => 'server.crt', 19 | 20 | /* 21 | * Authentication source to use. Must be one that is configured in 22 | * 'config/authsources.php'. 23 | */ 24 | 'auth' => 'example-userpass', 25 | 26 | 'SingleSignOnServiceBinding' => array( 27 | 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', 28 | 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', 29 | ), 30 | 31 | 'SingleLogoutServiceBinding' => array( 32 | 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', 33 | 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', 34 | ), 35 | 36 | 'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', 37 | //'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384', 38 | //'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512', 39 | 40 | 'redirect.sign' => FALSE, 41 | 'redirect.validate' => FALSE, 42 | 43 | 'saml20.sign.response' => TRUE, 44 | 'saml20.sign.assertion' => TRUE, 45 | 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', 46 | 'nameid.encryption' => FALSE, 47 | 'assertion.encryption' => FALSE, 48 | ); 49 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/LiveTest/users.php: -------------------------------------------------------------------------------- 1 | array( 6 | 'core:AdminPassword', 7 | ), 8 | 9 | 'example-userpass' => array( 10 | 'exampleauth:UserPass', 11 | 'user1:user1pass' => array( 12 | 'uid' => array('user1'), 13 | 'eduPersonAffiliation' => array('group1'), 14 | 'email' => 'user1@example.com', 15 | 'displayName' => 'User 1' 16 | ), 17 | 'user2:user2pass' => array( 18 | 'uid' => array('user2'), 19 | 'eduPersonAffiliation' => array('group2'), 20 | 'email' => 'user2@example.com', 21 | 'displayName' => 'User 2' 22 | ), 23 | ), 24 | 25 | ); -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/OpenSamlWrapperTest/metadataWrapper/metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | MIIDXTCCAkWgAwIBAgIJALmVVuDWu4NYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMjMxMTQzNDQ3WhcNNDgwNjI1MTQzNDQ3WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUCFozgNb1h1M0jzNRSCjhOBnR+uVbVpaWfXYIR+AhWDdEe5ryY+CgavOg8bfLybyzFdehlYdDRgkedEB/GjG8aJw06l0qF4jDOAw0kEygWCu2mcH7XOxRt+YAH3TVHa/Hu1W3WjzkobqqqLQ8gkKWWM27fOgAZ6GieaJBN6VBSMMcPey3HWLBmc+TYJmv1dbaO2jHhKh8pfKw0W12VM8P1PIO8gv4Phu/uuJYieBWKixBEyy0lHjyixYFCR12xdh4CA47q958ZRGnnDUGFVE1QhgRacJCOZ9bd5t9mr8KLaVBYTCJo5ERE8jymab5dPqe5qKfJsCZiqWglbjUo9twIDAQABo1AwTjAdBgNVHQ4EFgQUxpuwcs/CYQOyui+r1G+3KxBNhxkwHwYDVR0jBBgwFoAUxpuwcs/CYQOyui+r1G+3KxBNhxkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAAiWUKs/2x/viNCKi3Y6blEuCtAGhzOOZ9EjrvJ8+COH3Rag3tVBWrcBZ3/uhhPq5gy9lqw4OkvEws99/5jFsX1FJ6MKBgqfuy7yh5s1YfM0ANHYczMmYpZeAcQf2CGAaVfwTTfSlzNLsF2lW/ly7yapFzlYSJLGoVE+OHEu8g5SlNACUEfkXw+5Eghh+KzlIN7R6Q7r2ixWNFBC/jWf7NKUfJyX8qIG5md1YUeT6GBW9Bm2/1/RiO24JTaYlfLdKK9TYb8sG5B+OLab2DImG99CJ25RkAcSobWNF5zD0O6lgOo3cEdB/ksCq3hmtlC/DlLZ/D8CJ+7VuZnS1rR2naQ== 8 | 9 | 10 | 11 | 12 | 13 | 14 | MIIDXTCCAkWgAwIBAgIJALmVVuDWu4NYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMjMxMTQzNDQ3WhcNNDgwNjI1MTQzNDQ3WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUCFozgNb1h1M0jzNRSCjhOBnR+uVbVpaWfXYIR+AhWDdEe5ryY+CgavOg8bfLybyzFdehlYdDRgkedEB/GjG8aJw06l0qF4jDOAw0kEygWCu2mcH7XOxRt+YAH3TVHa/Hu1W3WjzkobqqqLQ8gkKWWM27fOgAZ6GieaJBN6VBSMMcPey3HWLBmc+TYJmv1dbaO2jHhKh8pfKw0W12VM8P1PIO8gv4Phu/uuJYieBWKixBEyy0lHjyixYFCR12xdh4CA47q958ZRGnnDUGFVE1QhgRacJCOZ9bd5t9mr8KLaVBYTCJo5ERE8jymab5dPqe5qKfJsCZiqWglbjUo9twIDAQABo1AwTjAdBgNVHQ4EFgQUxpuwcs/CYQOyui+r1G+3KxBNhxkwHwYDVR0jBBgwFoAUxpuwcs/CYQOyui+r1G+3KxBNhxkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAAiWUKs/2x/viNCKi3Y6blEuCtAGhzOOZ9EjrvJ8+COH3Rag3tVBWrcBZ3/uhhPq5gy9lqw4OkvEws99/5jFsX1FJ6MKBgqfuy7yh5s1YfM0ANHYczMmYpZeAcQf2CGAaVfwTTfSlzNLsF2lW/ly7yapFzlYSJLGoVE+OHEu8g5SlNACUEfkXw+5Eghh+KzlIN7R6Q7r2ixWNFBC/jWf7NKUfJyX8qIG5md1YUeT6GBW9Bm2/1/RiO24JTaYlfLdKK9TYb8sG5B+OLab2DImG99CJ25RkAcSobWNF5zD0O6lgOo3cEdB/ksCq3hmtlC/DlLZ/D8CJ+7VuZnS1rR2naQ== 15 | 16 | 17 | 18 | 19 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlCrumbExclusionTest/testReadSimpleConfiguration/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jenkins.security.s2m.MasterKillSwitchWarning 5 | 6 | 2.7.20 7 | 2 8 | NORMAL 9 | true 10 | 11 | false 12 | 13 | 14 | urn:mace:dir:attribute-def:displayName 15 | urn:mace:dir:attribute-def:groups 16 | 86400 17 | 18 | <?xml version="1.0"?> 19 | <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="simpleSAMLphpIdpHosted"> 20 | <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> 21 | <md:KeyDescriptor use="signing"> 22 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 23 | <ds:X509Data> 24 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 25 | </ds:X509Data> 26 | </ds:KeyInfo> 27 | </md:KeyDescriptor> 28 | <md:KeyDescriptor use="encryption"> 29 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 30 | <ds:X509Data> 31 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 32 | </ds:X509Data> 33 | </ds:KeyInfo> 34 | </md:KeyDescriptor> 35 | <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SingleLogoutService.php"/> 36 | <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat> 37 | <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SSOService.php"/> 38 | </md:IDPSSODescriptor> 39 | <md:ContactPerson contactType="technical"> 40 | <md:GivenName>Administrator</md:GivenName> 41 | <md:EmailAddress>dublindev@glgroup.com</md:EmailAddress> 42 | </md:ContactPerson> 43 | </md:EntityDescriptor> 44 | 45 | none 46 | urn:mace:dir:attribute-def:uid 47 | urn:mace:dir:attribute-def:mail 48 | 49 | false 50 | 51 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 52 | ${ITEM_ROOTDIR}/builds 53 | 54 | 55 | 56 | 57 | 58 | 5 59 | 0 60 | 61 | 62 | 63 | All 64 | false 65 | false 66 | 67 | 68 | 69 | All 70 | 8250 71 | 75 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlFormValidationsTest/testReadSimpleConfigurationAdvancedConfiguration/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jenkins.security.s2m.MasterKillSwitchWarning 5 | 6 | 2.7.20 7 | 2 8 | NORMAL 9 | true 10 | 11 | false 12 | 13 | 14 | urn:mace:dir:attribute-def:displayName 15 | urn:mace:dir:attribute-def:groups 16 | 86400 17 | 18 | <?xml version="1.0"?> 19 | <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="simpleSAMLphpIdpHosted"> 20 | <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> 21 | <md:KeyDescriptor use="signing"> 22 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 23 | <ds:X509Data> 24 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 25 | </ds:X509Data> 26 | </ds:KeyInfo> 27 | </md:KeyDescriptor> 28 | <md:KeyDescriptor use="encryption"> 29 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 30 | <ds:X509Data> 31 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 32 | </ds:X509Data> 33 | </ds:KeyInfo> 34 | </md:KeyDescriptor> 35 | <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SingleLogoutService.php"/> 36 | <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat> 37 | <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SSOService.php"/> 38 | </md:IDPSSODescriptor> 39 | <md:ContactPerson contactType="technical"> 40 | <md:GivenName>Administrator</md:GivenName> 41 | <md:EmailAddress>dublindev@glgroup.com</md:EmailAddress> 42 | </md:ContactPerson> 43 | </md:EntityDescriptor> 44 | 45 | none 46 | urn:mace:dir:attribute-def:uid 47 | 48 | /home/jdk/keystore 49 | 50 | 51 | true 52 | anotherContext 53 | spEntityId 54 | 55 | 56 | false 57 | 58 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 59 | ${ITEM_ROOTDIR}/builds 60 | 61 | 62 | 63 | 64 | 65 | 5 66 | 0 67 | 68 | 69 | 70 | All 71 | false 72 | false 73 | 74 | 75 | 76 | All 77 | 8250 78 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/samlProfileWithEmptyGroups/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jenkins.security.s2m.MasterKillSwitchWarning 5 | 6 | 2.7.20 7 | 2 8 | NORMAL 9 | true 10 | 11 | false 12 | 13 | 14 | urn:mace:dir:attribute-def:displayName 15 | urn:mace:dir:attribute-def:groups 16 | 86400 17 | 18 | <?xml version="1.0"?> 19 | <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="simpleSAMLphpIdpHosted"> 20 | <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> 21 | <md:KeyDescriptor use="signing"> 22 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 23 | <ds:X509Data> 24 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 25 | </ds:X509Data> 26 | </ds:KeyInfo> 27 | </md:KeyDescriptor> 28 | <md:KeyDescriptor use="encryption"> 29 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 30 | <ds:X509Data> 31 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 32 | </ds:X509Data> 33 | </ds:KeyInfo> 34 | </md:KeyDescriptor> 35 | <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SingleLogoutService.php"/> 36 | <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat> 37 | <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SSOService.php"/> 38 | </md:IDPSSODescriptor> 39 | <md:ContactPerson contactType="technical"> 40 | <md:GivenName>Administrator</md:GivenName> 41 | <md:EmailAddress>dublindev@glgroup.com</md:EmailAddress> 42 | </md:ContactPerson> 43 | </md:EntityDescriptor> 44 | 45 | none 46 | urn:mace:dir:attribute-def:uid 47 | urn:mace:dir:attribute-def:mail 48 | 49 | false 50 | 51 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 52 | ${ITEM_ROOTDIR}/builds 53 | 54 | 55 | 56 | 57 | 58 | 5 59 | 0 60 | 61 | 62 | 63 | All 64 | false 65 | false 66 | 67 | 68 | 69 | All 70 | 8250 71 | 75 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testHugeNumberOfUsers/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.642.4 5 | 2 6 | NORMAL 7 | true 8 | 9 | 10 | urn:mace:dir:attribute-def:displayName 11 | urn:mace:dir:attribute-def:groups 12 | 86400 13 | urn:mace:dir:attribute-def:mail 14 | 15 | <?xml version="1.0"?> 16 | <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="simpleSAMLphpIdpHosted"> 17 | <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> 18 | <md:KeyDescriptor use="signing"> 19 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 20 | <ds:X509Data> 21 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 22 | </ds:X509Data> 23 | </ds:KeyInfo> 24 | </md:KeyDescriptor> 25 | <md:KeyDescriptor use="encryption"> 26 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 27 | <ds:X509Data> 28 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 29 | </ds:X509Data> 30 | </ds:KeyInfo> 31 | </md:KeyDescriptor> 32 | <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:58080/simplesaml/saml2/idp/SingleLogoutService.php"/> 33 | <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat> 34 | <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:58080/simplesaml/saml2/idp/SSOService.php"/> 35 | </md:IDPSSODescriptor> 36 | <md:ContactPerson contactType="technical"> 37 | <md:GivenName>Administrator</md:GivenName> 38 | <md:EmailAddress>dublindev@glgroup.com</md:EmailAddress> 39 | </md:ContactPerson> 40 | </md:EntityDescriptor> 41 | 42 | none 43 | urn:mace:dir:attribute-def:uid 44 | 45 | false 46 | 47 | ${ITEM_ROOTDIR}/workspace 48 | ${ITEM_ROOTDIR}/builds 49 | 50 | 51 | 52 | 53 | 54 | 5 55 | 0 56 | 57 | 58 | 59 | all 60 | false 61 | false 62 | 63 | 64 | 65 | all 66 | 0 67 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfiguration/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jenkins.security.s2m.MasterKillSwitchWarning 5 | 6 | 2.7.20 7 | 2 8 | NORMAL 9 | true 10 | 11 | false 12 | 13 | 14 | urn:mace:dir:attribute-def:displayName 15 | urn:mace:dir:attribute-def:groups 16 | 86400 17 | 18 | <?xml version="1.0"?> 19 | <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="simpleSAMLphpIdpHosted"> 20 | <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> 21 | <md:KeyDescriptor use="signing"> 22 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 23 | <ds:X509Data> 24 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 25 | </ds:X509Data> 26 | </ds:KeyInfo> 27 | </md:KeyDescriptor> 28 | <md:KeyDescriptor use="encryption"> 29 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 30 | <ds:X509Data> 31 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 32 | </ds:X509Data> 33 | </ds:KeyInfo> 34 | </md:KeyDescriptor> 35 | <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SingleLogoutService.php"/> 36 | <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat> 37 | <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SSOService.php"/> 38 | </md:IDPSSODescriptor> 39 | <md:ContactPerson contactType="technical"> 40 | <md:GivenName>Administrator</md:GivenName> 41 | <md:EmailAddress>dublindev@glgroup.com</md:EmailAddress> 42 | </md:ContactPerson> 43 | </md:EntityDescriptor> 44 | 45 | none 46 | urn:mace:dir:attribute-def:uid 47 | urn:mace:dir:attribute-def:mail 48 | 49 | false 50 | 51 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 52 | ${ITEM_ROOTDIR}/builds 53 | 54 | 55 | 56 | 57 | 58 | 5 59 | 0 60 | 61 | 62 | 63 | All 64 | false 65 | false 66 | 67 | 68 | 69 | All 70 | 8250 71 | 75 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationAdvancedConfiguration/secrets/hudson.util.Secret: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationAdvancedConfiguration/secrets/hudson.util.Secret -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationAdvancedConfiguration/secrets/jenkins.model.Jenkins.crumbSalt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationAdvancedConfiguration/secrets/jenkins.model.Jenkins.crumbSalt -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationAdvancedConfiguration/secrets/master.key: -------------------------------------------------------------------------------- 1 | 576ec0fdb6d242def035eed001c77707add5033b57027c7bda5006a16c3e7ceb71b7d0a907d4894ace69270dea8af9c1064ff4553d83035790eaaf5efb887c84dc575b7319744c82aaa0cc0234d66dc477aed3f6d2993dcd281e76cb87d9f6f7ce9f7d9ba0ff87e0da0b23e7fe469db3bc12e144f1284d3b16a59e8ee5dc1c3f -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationAdvancedConfiguration/secrets/org.jenkinsci.main.modules.instance_identity.InstanceIdentity.KEY: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationAdvancedConfiguration/secrets/org.jenkinsci.main.modules.instance_identity.InstanceIdentity.KEY -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationEncryptionData/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jenkins.security.s2m.MasterKillSwitchWarning 5 | 6 | 2.7.20 7 | 2 8 | NORMAL 9 | true 10 | 11 | false 12 | 13 | 14 | urn:mace:dir:attribute-def:displayName 15 | urn:mace:dir:attribute-def:groups 16 | 86400 17 | 18 | <?xml version="1.0"?> 19 | <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="simpleSAMLphpIdpHosted"> 20 | <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> 21 | <md:KeyDescriptor use="signing"> 22 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 23 | <ds:X509Data> 24 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 25 | </ds:X509Data> 26 | </ds:KeyInfo> 27 | </md:KeyDescriptor> 28 | <md:KeyDescriptor use="encryption"> 29 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 30 | <ds:X509Data> 31 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 32 | </ds:X509Data> 33 | </ds:KeyInfo> 34 | </md:KeyDescriptor> 35 | <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SingleLogoutService.php"/> 36 | <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat> 37 | <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SSOService.php"/> 38 | </md:IDPSSODescriptor> 39 | <md:ContactPerson contactType="technical"> 40 | <md:GivenName>Administrator</md:GivenName> 41 | <md:EmailAddress>dublindev@glgroup.com</md:EmailAddress> 42 | </md:ContactPerson> 43 | </md:EntityDescriptor> 44 | 45 | none 46 | urn:mace:dir:attribute-def:uid 47 | 48 | /home/jdk/keystore 49 | {AQAAABAAAAAQmWC5FpWr022ce0bloF99XbtBv/vWtqe5jY3CVnO0VXs=} 50 | {AQAAABAAAAAQy42AWPl+ya+mPpwFlp4b/Nt5JJ0Ba62Ov5PTbtQGqKg=} 51 | 52 | 53 | false 54 | 55 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 56 | ${ITEM_ROOTDIR}/builds 57 | 58 | 59 | 60 | 61 | 62 | 5 63 | 0 64 | 65 | 66 | 67 | All 68 | false 69 | false 70 | 71 | 72 | 73 | All 74 | 8250 75 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationEncryptionData/secrets/hudson.util.Secret: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationEncryptionData/secrets/hudson.util.Secret -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationEncryptionData/secrets/jenkins.model.Jenkins.crumbSalt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationEncryptionData/secrets/jenkins.model.Jenkins.crumbSalt -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationEncryptionData/secrets/master.key: -------------------------------------------------------------------------------- 1 | 576ec0fdb6d242def035eed001c77707add5033b57027c7bda5006a16c3e7ceb71b7d0a907d4894ace69270dea8af9c1064ff4553d83035790eaaf5efb887c84dc575b7319744c82aaa0cc0234d66dc477aed3f6d2993dcd281e76cb87d9f6f7ce9f7d9ba0ff87e0da0b23e7fe469db3bc12e144f1284d3b16a59e8ee5dc1c3f -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationEncryptionData/secrets/org.jenkinsci.main.modules.instance_identity.InstanceIdentity.KEY: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/saml-plugin/ebb329cb12642ddfea8173f86fb637a56f8dabbd/src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationEncryptionData/secrets/org.jenkinsci.main.modules.instance_identity.InstanceIdentity.KEY -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationLowercase/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jenkins.security.s2m.MasterKillSwitchWarning 5 | 6 | 2.7.20 7 | 2 8 | NORMAL 9 | true 10 | 11 | false 12 | 13 | 14 | urn:mace:dir:attribute-def:displayName 15 | urn:mace:dir:attribute-def:groups 16 | 86400 17 | 18 | <?xml version="1.0"?> 19 | <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="simpleSAMLphpIdpHosted"> 20 | <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> 21 | <md:KeyDescriptor use="signing"> 22 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 23 | <ds:X509Data> 24 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 25 | </ds:X509Data> 26 | </ds:KeyInfo> 27 | </md:KeyDescriptor> 28 | <md:KeyDescriptor use="encryption"> 29 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 30 | <ds:X509Data> 31 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 32 | </ds:X509Data> 33 | </ds:KeyInfo> 34 | </md:KeyDescriptor> 35 | <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SingleLogoutService.php"/> 36 | <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat> 37 | <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SSOService.php"/> 38 | </md:IDPSSODescriptor> 39 | <md:ContactPerson contactType="technical"> 40 | <md:GivenName>Administrator</md:GivenName> 41 | <md:EmailAddress>dublindev@glgroup.com</md:EmailAddress> 42 | </md:ContactPerson> 43 | </md:EntityDescriptor> 44 | 45 | lowercase 46 | urn:mace:dir:attribute-def:uid 47 | 48 | false 49 | 50 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 51 | ${ITEM_ROOTDIR}/builds 52 | 53 | 54 | 55 | 56 | 57 | 5 58 | 0 59 | 60 | 61 | 62 | All 63 | false 64 | false 65 | 66 | 67 | 68 | All 69 | 8250 70 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/testReadSimpleConfigurationUppercase/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jenkins.security.s2m.MasterKillSwitchWarning 5 | 6 | 2.7.20 7 | 2 8 | NORMAL 9 | true 10 | 11 | false 12 | 13 | 14 | urn:mace:dir:attribute-def:displayName 15 | urn:mace:dir:attribute-def:groups 16 | 86400 17 | 18 | <?xml version="1.0"?> 19 | <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="simpleSAMLphpIdpHosted"> 20 | <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> 21 | <md:KeyDescriptor use="signing"> 22 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 23 | <ds:X509Data> 24 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 25 | </ds:X509Data> 26 | </ds:KeyInfo> 27 | </md:KeyDescriptor> 28 | <md:KeyDescriptor use="encryption"> 29 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 30 | <ds:X509Data> 31 | <ds:X509Certificate>MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es=</ds:X509Certificate> 32 | </ds:X509Data> 33 | </ds:KeyInfo> 34 | </md:KeyDescriptor> 35 | <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SingleLogoutService.php"/> 36 | <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat> 37 | <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:58080/simplesaml/saml2/idp/SSOService.php"/> 38 | </md:IDPSSODescriptor> 39 | <md:ContactPerson contactType="technical"> 40 | <md:GivenName>Administrator</md:GivenName> 41 | <md:EmailAddress>dublindev@glgroup.com</md:EmailAddress> 42 | </md:ContactPerson> 43 | </md:EntityDescriptor> 44 | 45 | uppercase 46 | urn:mace:dir:attribute-def:uid 47 | 48 | false 49 | 50 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 51 | ${ITEM_ROOTDIR}/builds 52 | 53 | 54 | 55 | 56 | 57 | 5 58 | 0 59 | 60 | 61 | 62 | All 63 | false 64 | false 65 | 66 | 67 | 68 | All 69 | 8250 70 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/SamlSecurityRealmTest/upgradeIDPMetadataFileTest/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.0 5 | 2 6 | NORMAL 7 | true 8 | 9 | 10 | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name 11 | http://schemas.xmlsoap.org/claims/Group 12 | 86400 13 | email 14 | 15 | <?xml version="1.0"?> 16 | <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="http://192.168.99.100:8080/simplesaml/saml2/idp/metadata.php"> 17 | <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> 18 | <md:KeyDescriptor use="signing"> 19 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 20 | <ds:X509Data> 21 | <ds:X509Certificate>MIIDXTCCAkWgAwIBAgIJALmVVuDWu4NYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMjMxMTQzNDQ3WhcNNDgwNjI1MTQzNDQ3WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUCFozgNb1h1M0jzNRSCjhOBnR+uVbVpaWfXYIR+AhWDdEe5ryY+CgavOg8bfLybyzFdehlYdDRgkedEB/GjG8aJw06l0qF4jDOAw0kEygWCu2mcH7XOxRt+YAH3TVHa/Hu1W3WjzkobqqqLQ8gkKWWM27fOgAZ6GieaJBN6VBSMMcPey3HWLBmc+TYJmv1dbaO2jHhKh8pfKw0W12VM8P1PIO8gv4Phu/uuJYieBWKixBEyy0lHjyixYFCR12xdh4CA47q958ZRGnnDUGFVE1QhgRacJCOZ9bd5t9mr8KLaVBYTCJo5ERE8jymab5dPqe5qKfJsCZiqWglbjUo9twIDAQABo1AwTjAdBgNVHQ4EFgQUxpuwcs/CYQOyui+r1G+3KxBNhxkwHwYDVR0jBBgwFoAUxpuwcs/CYQOyui+r1G+3KxBNhxkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAAiWUKs/2x/viNCKi3Y6blEuCtAGhzOOZ9EjrvJ8+COH3Rag3tVBWrcBZ3/uhhPq5gy9lqw4OkvEws99/5jFsX1FJ6MKBgqfuy7yh5s1YfM0ANHYczMmYpZeAcQf2CGAaVfwTTfSlzNLsF2lW/ly7yapFzlYSJLGoVE+OHEu8g5SlNACUEfkXw+5Eghh+KzlIN7R6Q7r2ixWNFBC/jWf7NKUfJyX8qIG5md1YUeT6GBW9Bm2/1/RiO24JTaYlfLdKK9TYb8sG5B+OLab2DImG99CJ25RkAcSobWNF5zD0O6lgOo3cEdB/ksCq3hmtlC/DlLZ/D8CJ+7VuZnS1rR2naQ==</ds:X509Certificate> 22 | </ds:X509Data> 23 | </ds:KeyInfo> 24 | </md:KeyDescriptor> 25 | <md:KeyDescriptor use="encryption"> 26 | <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 27 | <ds:X509Data> 28 | <ds:X509Certificate>MIIDXTCCAkWgAwIBAgIJALmVVuDWu4NYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMjMxMTQzNDQ3WhcNNDgwNjI1MTQzNDQ3WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUCFozgNb1h1M0jzNRSCjhOBnR+uVbVpaWfXYIR+AhWDdEe5ryY+CgavOg8bfLybyzFdehlYdDRgkedEB/GjG8aJw06l0qF4jDOAw0kEygWCu2mcH7XOxRt+YAH3TVHa/Hu1W3WjzkobqqqLQ8gkKWWM27fOgAZ6GieaJBN6VBSMMcPey3HWLBmc+TYJmv1dbaO2jHhKh8pfKw0W12VM8P1PIO8gv4Phu/uuJYieBWKixBEyy0lHjyixYFCR12xdh4CA47q958ZRGnnDUGFVE1QhgRacJCOZ9bd5t9mr8KLaVBYTCJo5ERE8jymab5dPqe5qKfJsCZiqWglbjUo9twIDAQABo1AwTjAdBgNVHQ4EFgQUxpuwcs/CYQOyui+r1G+3KxBNhxkwHwYDVR0jBBgwFoAUxpuwcs/CYQOyui+r1G+3KxBNhxkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAAiWUKs/2x/viNCKi3Y6blEuCtAGhzOOZ9EjrvJ8+COH3Rag3tVBWrcBZ3/uhhPq5gy9lqw4OkvEws99/5jFsX1FJ6MKBgqfuy7yh5s1YfM0ANHYczMmYpZeAcQf2CGAaVfwTTfSlzNLsF2lW/ly7yapFzlYSJLGoVE+OHEu8g5SlNACUEfkXw+5Eghh+KzlIN7R6Q7r2ixWNFBC/jWf7NKUfJyX8qIG5md1YUeT6GBW9Bm2/1/RiO24JTaYlfLdKK9TYb8sG5B+OLab2DImG99CJ25RkAcSobWNF5zD0O6lgOo3cEdB/ksCq3hmtlC/DlLZ/D8CJ+7VuZnS1rR2naQ==</ds:X509Certificate> 29 | </ds:X509Data> 30 | </ds:KeyInfo> 31 | </md:KeyDescriptor> 32 | <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:8080/simplesaml/saml2/idp/SingleLogoutService.php"/> 33 | <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat> 34 | <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://192.168.99.100:8080/simplesaml/saml2/idp/SSOService.php"/> 35 | </md:IDPSSODescriptor> 36 | </md:EntityDescriptor> 37 | 38 | none 39 | uid 40 | 41 | true 42 | jenkins-dev 43 | 44 | 45 | false 46 | 47 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 48 | ${ITEM_ROOTDIR}/builds 49 | 50 | 51 | 52 | 53 | 54 | 0 55 | 56 | 57 | 58 | All 59 | false 60 | false 61 | 62 | 63 | 64 | All 65 | 0 66 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/saml/configuration-as-code.yaml: -------------------------------------------------------------------------------- 1 | jenkins: 2 | securityRealm: 3 | saml: 4 | advancedConfiguration: 5 | authnContextClassRef: "anotherContext" 6 | forceAuthn: true 7 | spEntityId: "mySpEntityId" 8 | binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" 9 | displayNameAttributeName: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" 10 | emailAttributeName: "fake@mail.com" 11 | encryptionData: 12 | forceSignRedirectBindingAuthnRequest: true 13 | keystorePassword: "{AQAAABAAAAAQW05cASi2RE3zzrl9xskAhhuYAamBbQe0k5Bk9lkDd80=}" 14 | keystorePath: "/home/jdk/keystore" 15 | privateKeyAlias: "privatealias" 16 | privateKeyPassword: "{AQAAABAAAAAQ40qxDUu7fjfmHst04RrBvBm24Om5JBeKAYLnA/9OXZk=}" 17 | groupsAttributeName: "http://schemas.xmlsoap.org/claims/Group" 18 | idpMetadataConfiguration: 19 | period: 2 20 | url: "http://fake.ldP.metadata.url" 21 | xml: |- 22 | 23 | 24 | 25 | 26 | 27 | 28 | MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es= 29 | 30 | 31 | 32 | 33 | 34 | 35 | MIIDtTCCAp2gAwIBAgIJAINeCx9sdNHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE4MTcyMDAwWhcNMjYxMTE4MTcyMDAwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkbkG/8UGDrqNUCpCn3NXGQqG0+oHXeU+htHXash6zhcYb45se+lRoISgh6vSlc2NOVVuNBf1lrFziKdi5dvnbLKkxL+0SOww3ZP3VttzrE1Fk7ZXCU4o2x5P7Mt3UXyx4Ik10OCEybhdR57EuGXnc14QCOn3OH/d05bzlh8WpVz5FrqPmhpGwsqtqwC4CAHWszbklA9nc6jeNwGqeb6JUez6OihBxSUoHulyjqsnNYGobmmK85DSxmZe8uT8SO3xHRvn6UYYjxckh2XzR/NVh+sDEZjCZLP1J9py2MT4HFBh252SNDbboh0BC3/qCmwK/IS0fMy2W/08g6RJwGlkVQIDAQABo4GnMIGkMB0GA1UdDgQWBBQIUCMMqKSMB7npenjd6uiK4QsLljB1BgNVHSMEbjBsgBQIUCMMqKSMB7npenjd6uiK4QsLlqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAINeCx9sdNHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFppKlxgIeYGgM5AnC+1d2btAel0tIX8zYWnDnCcjKyEJTM8ztGq/fXz8KMhTbmtD1ITD5DGaAyEPCRpSoLXybXtp/OeVMO+hNjh+RGV8jSzjSnbMY/cWClYz+v+oW9+CxVN+k6KYPHRrSSDtmOyUVg7NcQnJoPXV7Ch9UKW4oCkom9+rcRYjCTFBq9jsj38OcwRIWLqGa+E8QG26H+MT24B7bSxWakajwjYCFdcI5QA9vEL5q5ZBd8rt2yzlAXZ2bMOynq7gvkg2Yt5uzWeGu0IBonbceEwwQ9Eyid0x4mNg9s8F3e9oMRpvsnA3gm60znRR1jEomFOIVpJoIjU9es= 36 | 37 | 38 | 39 | 40 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 41 | 42 | 43 | 44 | Administrator 45 | dublindev@glgroup.com 46 | 47 | 48 | logoutUrl: "http://fake.logout.url" 49 | maximumAuthenticationLifetime: 86400 50 | samlCustomAttributes: 51 | - attribute: 52 | displayName: "display1" 53 | name: "attribute1" 54 | - attribute: 55 | displayName: "display2" 56 | name: "attribute2" 57 | usernameAttributeName: "urn:mace:dir:attribute-def:uid" 58 | usernameCaseConversion: "none" 59 | --------------------------------------------------------------------------------