├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── authentication-provider ├── pom.xml └── src │ ├── main │ ├── java │ │ └── livelessons │ │ │ ├── custom │ │ │ └── AuthenticationProviderApplication.java │ │ │ └── ldap │ │ │ └── LdapAuthenticationApplication.java │ └── resources │ │ ├── application-ldap.properties │ │ └── test-server.ldif │ └── test │ └── java │ └── livelessons │ ├── custom │ ├── AtlassianCrowdAuthenticationProviderTest.java │ └── AuthenticationProviderApplicationTest.java │ └── ldap │ └── LdapAuthenticationApplicationTest.java ├── login ├── pom.xml └── src │ ├── main │ ├── java │ │ └── livelessons │ │ │ └── LoginApplication.java │ └── resources │ │ ├── application.properties │ │ └── templates │ │ ├── hidden.html │ │ ├── layout.html │ │ ├── login.html │ │ └── logout.html │ └── test │ ├── java │ └── livelessons │ │ ├── LoginApplicationTests.java │ │ └── webdriver │ │ ├── HiddenPage.java │ │ └── LoginPage.java │ └── resources │ └── logback-test.xml ├── password-migration ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── passwordmigration │ │ │ ├── CustomAuthenticationApplication.java │ │ │ ├── CustomSecurityConfiguration.java │ │ │ ├── CustomUserDetails.java │ │ │ ├── CustomUserDetailsService.java │ │ │ └── GreetingRestController.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── passwordmigration │ └── PasswordMigrationApplicationTests.java ├── pom.xml ├── studio ├── auditing │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── customauthentication │ │ │ │ └── CustomAuthenticationApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── customauthentication │ │ └── CustomAuthenticationApplicationTests.java ├── custom-authentication │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── customauthentication │ │ │ │ └── CustomAuthenticationApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── customauthentication │ │ └── CustomAuthenticationApplicationTests.java ├── inmemory │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── inmemory │ │ │ │ └── InmemoryApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── inmemory │ │ └── InmemoryApplicationTests.java ├── jdbc │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── jdbc │ │ │ │ └── JdbcApplication.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── schema.sql │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── jdbc │ │ └── JdbcApplicationTests.java ├── ldap │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── ldap │ │ │ │ └── LdapApplication.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── test-server.ldif │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── ldap │ │ └── LdapApplicationTests.java ├── login │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── login │ │ │ │ └── LoginApplication.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── templates │ │ │ ├── hidden.html │ │ │ ├── layout.html │ │ │ ├── login.html │ │ │ └── logout.html │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── login │ │ └── LoginApplicationTests.java └── password-encoding-and-migration │ ├── .gitignore │ ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── customauthentication │ │ │ └── CustomAuthenticationApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── customauthentication │ └── CustomAuthenticationApplicationTests.java ├── user-details ├── pom.xml └── src │ ├── main │ ├── java │ │ └── livelessons │ │ │ └── AuthenticationApplication.java │ └── resources │ │ ├── application.properties │ │ └── schema.sql │ └── test │ └── java │ └── livelessons │ ├── JdbcUserDetailsServiceTest.java │ ├── MemoryUserDetailsServiceTest.java │ ├── SimpleUserDetailsServiceTest.java │ └── UserDetailsServiceTestBaseClass.java ├── xauth-app ├── pom.xml └── src │ ├── main │ ├── java │ │ └── livelessons │ │ │ └── custom │ │ │ └── CustomApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── livelessons │ └── custom │ └── GreetingsRestControllerTest.java └── xauth ├── pom.xml └── src └── main ├── java └── livelessons │ └── xauth │ ├── TokenUtils.java │ ├── XAuthAutoConfiguration.java │ ├── XAuthConfiguration.java │ ├── XAuthDslConfigurer.java │ ├── XAuthTokenFilter.java │ └── XAuthTokenRestController.java └── resources ├── META-INF └── spring.factories └── application.properties /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea 3 | *.iml 4 | pom.xml.tag 5 | pom.xml.releaseBackup 6 | pom.xml.versionsBackup 7 | pom.xml.next 8 | release.properties 9 | dependency-reduced-pom.xml 10 | buildNumber.properties 11 | .mvn/timing.properties 12 | 13 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 14 | !/.mvn/wrapper/maven-wrapper.jar 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - oraclejdk8 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Authentication 2 | - problems with HTTP basic requires validation on every request. ur passing credentials every request! bad. more surface area. plus if u r encoding ur passwords properly it should take half a second to a second. which means this is slow. in authentication world u'd normally exchange long term credentials for a short term credentials. it takes longer to rotate username/password than a short term credential. also, people often reuse user/passwords so if its compromised then it has a larger impact than a short term creential which is secure random generated. SO, use some other mechanism. u use http basic to transport user/pw and exchange it for short term credentials. this is what youre doing in a form login. the other bad thing about http basic in a browser is that u can't logout. the only way to get out of the lopo is to close the whole browser. so, well use a proper authentication mechanism like a form login. 3 | 4 | - why user details? its har to get password encoding correct. u want to make sure u get password encoding correct. u want to make sure u get all the details correct. if the user doesnt exist we dont want to reveal the user that is missing. there are side channel attacks like figuring out if the user exists based on how long it takes to process the request. if a user does exist, given what we know about password encoding, it should take something like .5 -1s. but naive code (from the pOV of security) might take much less time for somebody who DOESNT exist, because there's no password to validate. the correct performance engineering approach here, to return quickly, would be the wrong thing to do from a security pov. if the user doesnt exist, Spring Security has a dummy password that we always compare against. also, we want to avoid session fixation attacks by changing the JSESSIONID on login (when we promote a regular http session to an authenticated session). we also need to rotate the csrf token. 5 | 6 | - LDAP: dn = domain name (a hierarchy to find the current user, or anythign in LDAP). LDAP is a tree structure. `uid={0},ou=people` says find a UID leaf under the people branch. user info is in one tree, and groups (roles/autorities) are stored in another. so we must psecify both queries. `ou=groups` does that. `ldap://localhost:8389/dc=springframework,dc=org` is the base URL for both groups and users. eg: `dc=springframework,dc=org,ou=people,uid=....` there are two type sof auth in ldap: BIND authentication. BIND is that whateve the user types for user and password u try to LDAP bind by presenting user/pw to directory an i tells u if the user/pw is correct. the other type, LDAP search, is password comparison wherein we submit a query, get results, an compare PW in spring security client java code. So, auth happens in LDAP bind on the LDAP server and auth happens in the spring security client in second type. the LDAP server usually has a password encoding approach. there are specific fields for passwords. as an app developer we reately have the ability to 'write' passwords to LDAP, omore often need to read from LDAP that exists for other purporses. its been installed by the organiation and we have to reuse it. so, while we could a) side step the password field and write passwords that we encode into some other field and b) mae spring security aware of this change c) read the passwords and compare them in the client code, this is impractical. so we use things like `LdapShaPasswordEncoder` , which you can see is deprecated but NOT going anywhere. its a warning! 7 | 8 | https://stackoverflow.com/questions/18756688/what-are-cn-ou-dc-in-an-ldap-search/18756876 9 | CN = Common Name 10 | OU = Organizational Unit 11 | DC = Domain Component 12 | These are all parts of the X.500 Directory Specification, which defines nodes in a LDAP directory. 13 | 14 | You can also read up on LDAP data Interchange Format (LDIF), which is an alternate format. 15 | 16 | You read it from right to left, the right-most component is the root of the tree, and the left most component is the node (or leaf) you want to reach. 17 | 18 | Each = pair is a search criteria. 19 | 20 | With your example query 21 | 22 | ("CN=Dev-India,OU=Distribution Groups,DC=gp,DC=gl,DC=google,DC=com"); 23 | In effect the query is: 24 | 25 | 26 | 27 | 28 | 1. this is plain text. use NoOpPasswordEncoder.getInstance() ; 29 | 2. in order to take advantage of the new password encode in Sing security u need to migrate existing passwords. 30 | 3. if u are using plaint text that amounts to prefixing it whatever the appropirate prefix. 31 | 4. now replace NooOPWEncoder w/ DelegatingPWencoder 32 | 5. now imagine u have a signup page and the new user signs up and uses BCrypt. Use the DelegatingPWEncoder to encode new strings. the default is bcrypt. 33 | 6. NEW! spring security UDS supports password migration through the UserDetailsPasswordService. Out of the box only InMemoryUDM supports this. the idea is simple. we want them to login and SS 34 | and ideally to change their password. SS will automatically check if the old password was stored in a insecure way and migrate to brcypt by invoking our UserDetailsPasswordService. 35 | All fo that logic is in the DaoAuthentiationProvider. It scostly to upgrade the encoding so we dont do this unless we need to 36 | But ur auth SHOULD support it. so the business/marketing could be any of a number of things. "weve changed terms of service. login." or "its been a month, password expired." or 37 | "we want to proactively protect u. taking additional measures." 38 | 7. there were two different PasswordEncoders in SS 4.2 39 | 8. if you are using the old password encoders u should see the migration javadocs in org.springframework.security.crypto.password.MessageDigestPasswordEncoder. 40 | 41 | 42 | Custom Authentication: use a REST controller to handle login by setting the SecurityContext...*. 43 | -------------------------------------------------------------------------------- /authentication-provider/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | authentication-provider 7 | 8 | livelessons 9 | authentication 10 | 0.0.1-SNAPSHOT 11 | .. 12 | 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-security 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-web 21 | 22 | 23 | org.springframework.ldap 24 | spring-ldap-core 25 | 26 | 27 | org.springframework.security 28 | spring-security-ldap 29 | 30 | 31 | com.unboundid 32 | unboundid-ldapsdk 33 | 34 | 35 | org.projectlombok 36 | lombok 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-test 41 | test 42 | 43 | 44 | org.springframework.security 45 | spring-security-test 46 | test 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /authentication-provider/src/main/java/livelessons/custom/AuthenticationProviderApplication.java: -------------------------------------------------------------------------------- 1 | package livelessons.custom; 2 | 3 | import org.apache.commons.logging.Log; 4 | import org.apache.commons.logging.LogFactory; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.security.authentication.AuthenticationProvider; 10 | import org.springframework.security.authentication.BadCredentialsException; 11 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 12 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 13 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 14 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 15 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 16 | import org.springframework.security.core.Authentication; 17 | import org.springframework.security.core.AuthenticationException; 18 | import org.springframework.security.core.authority.AuthorityUtils; 19 | import org.springframework.stereotype.Component; 20 | import org.springframework.web.bind.annotation.GetMapping; 21 | import org.springframework.web.bind.annotation.RestController; 22 | 23 | import java.security.Principal; 24 | 25 | @SpringBootApplication 26 | public class AuthenticationProviderApplication { 27 | 28 | public static void main(String args[]) { 29 | SpringApplication.run(AuthenticationProviderApplication.class, args); 30 | } 31 | 32 | @Configuration 33 | @EnableWebSecurity 34 | public static class BasicAuthorizationConfig extends WebSecurityConfigurerAdapter { 35 | 36 | private final AtlassianCrowdAuthenticationProvider authenticationProvider; 37 | 38 | public BasicAuthorizationConfig( 39 | AtlassianCrowdAuthenticationProvider authenticationProvider) { 40 | this.authenticationProvider = authenticationProvider; 41 | } 42 | 43 | @Override 44 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 45 | auth.authenticationProvider(this.authenticationProvider); 46 | } 47 | 48 | @Override 49 | protected void configure(HttpSecurity http) throws Exception { 50 | http.csrf().and().httpBasic().and().authorizeRequests().anyRequest() 51 | .authenticated(); 52 | } 53 | 54 | } 55 | 56 | } 57 | 58 | @RestController 59 | class GreetingsRestController { 60 | 61 | @GetMapping("/greet") 62 | String greet(Principal p) { 63 | return "hello, " + p.getName() + "!"; 64 | } 65 | 66 | } 67 | 68 | @Component 69 | class AtlassianCrowdAuthenticationProvider implements AuthenticationProvider { 70 | 71 | private final Log log = LogFactory.getLog(getClass()); 72 | 73 | // visible for testing. 74 | final String hardcodedUsername, hardcodedPassword; 75 | 76 | AtlassianCrowdAuthenticationProvider(@Value("${username:user}") String usr, 77 | @Value("${password:pw}") String pw) { 78 | this.hardcodedUsername = usr; 79 | this.hardcodedPassword = pw; 80 | } 81 | 82 | @Override 83 | public Authentication authenticate(Authentication authentication) 84 | throws AuthenticationException { 85 | 86 | String username = authentication.getName(); 87 | String password = authentication.getCredentials().toString(); 88 | 89 | if (isValid(username, password)) { 90 | return new UsernamePasswordAuthenticationToken(username, password, 91 | AuthorityUtils.createAuthorityList("USER")); 92 | } 93 | 94 | throw new BadCredentialsException( 95 | "couldn't authenticate (" + authentication + ")"); 96 | } 97 | 98 | private boolean isValid(String username, String password) { 99 | return (username.equalsIgnoreCase(this.hardcodedUsername) 100 | && password.equalsIgnoreCase(this.hardcodedPassword)); 101 | } 102 | 103 | @Override 104 | public boolean supports(Class authentication) { 105 | return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /authentication-provider/src/main/java/livelessons/ldap/LdapAuthenticationApplication.java: -------------------------------------------------------------------------------- 1 | package livelessons.ldap; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Profile; 7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 10 | import org.springframework.security.crypto.password.LdapShaPasswordEncoder; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.security.Principal; 15 | 16 | @SpringBootApplication 17 | public class LdapAuthenticationApplication { 18 | 19 | public static void main(String args[]) { 20 | SpringApplication.run(LdapAuthenticationApplication.class, args); 21 | } 22 | 23 | /** 24 | * @see What is 26 | * LDAP 27 | */ 28 | @Profile("ldap") 29 | @Configuration 30 | public static class LdapConfiguration extends WebSecurityConfigurerAdapter { 31 | 32 | @Override 33 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 34 | 35 | auth.ldapAuthentication().userDnPatterns("uid={0},ou=people") 36 | .groupSearchBase("ou=groups").contextSource() 37 | .url("ldap://localhost:8389/dc=springframework,dc=org").and() 38 | .passwordCompare().passwordEncoder(new LdapShaPasswordEncoder()) 39 | .passwordAttribute("userPassword"); 40 | } 41 | 42 | @Override 43 | protected void configure(HttpSecurity http) throws Exception { 44 | http.csrf().and().httpBasic().and().authorizeRequests().anyRequest() 45 | .authenticated(); 46 | } 47 | 48 | } 49 | 50 | } 51 | 52 | @RestController 53 | class GreetingsRestController { 54 | 55 | @GetMapping("/greet") 56 | String greet(Principal p) { 57 | return "hello, " + p.getName() + "!"; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /authentication-provider/src/main/resources/application-ldap.properties: -------------------------------------------------------------------------------- 1 | spring.ldap.embedded.ldif=classpath:test-server.ldif 2 | spring.ldap.embedded.base-dn=dc=springframework,dc=org 3 | spring.ldap.embedded.port=8389 -------------------------------------------------------------------------------- /authentication-provider/src/main/resources/test-server.ldif: -------------------------------------------------------------------------------- 1 | dn: dc=springframework,dc=org 2 | objectclass: top 3 | objectclass: domain 4 | objectclass: extensibleObject 5 | dc: springframework 6 | 7 | dn: ou=groups,dc=springframework,dc=org 8 | objectclass: top 9 | objectclass: organizationalUnit 10 | ou: groups 11 | 12 | dn: ou=subgroups,ou=groups,dc=springframework,dc=org 13 | objectclass: top 14 | objectclass: organizationalUnit 15 | ou: subgroups 16 | 17 | dn: ou=people,dc=springframework,dc=org 18 | objectclass: top 19 | objectclass: organizationalUnit 20 | ou: people 21 | 22 | dn: ou=space cadets,dc=springframework,dc=org 23 | objectclass: top 24 | objectclass: organizationalUnit 25 | ou: space cadets 26 | 27 | dn: ou=\"quoted people\",dc=springframework,dc=org 28 | objectclass: top 29 | objectclass: organizationalUnit 30 | ou: "quoted people" 31 | 32 | dn: ou=otherpeople,dc=springframework,dc=org 33 | objectclass: top 34 | objectclass: organizationalUnit 35 | ou: otherpeople 36 | 37 | dn: uid=ben,ou=people,dc=springframework,dc=org 38 | objectclass: top 39 | objectclass: person 40 | objectclass: organizationalPerson 41 | objectclass: inetOrgPerson 42 | cn: Ben Alex 43 | sn: Alex 44 | uid: ben 45 | userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ= 46 | 47 | dn: uid=bob,ou=people,dc=springframework,dc=org 48 | objectclass: top 49 | objectclass: person 50 | objectclass: organizationalPerson 51 | objectclass: inetOrgPerson 52 | cn: Bob Hamilton 53 | sn: Hamilton 54 | uid: bob 55 | userPassword: bobspassword 56 | 57 | dn: uid=joe,ou=otherpeople,dc=springframework,dc=org 58 | objectclass: top 59 | objectclass: person 60 | objectclass: organizationalPerson 61 | objectclass: inetOrgPerson 62 | cn: Joe Smeth 63 | sn: Smeth 64 | uid: joe 65 | userPassword: joespassword 66 | 67 | dn: cn=mouse\, jerry,ou=people,dc=springframework,dc=org 68 | objectclass: top 69 | objectclass: person 70 | objectclass: organizationalPerson 71 | objectclass: inetOrgPerson 72 | cn: Mouse, Jerry 73 | sn: Mouse 74 | uid: jerry 75 | userPassword: jerryspassword 76 | 77 | dn: cn=slash/guy,ou=people,dc=springframework,dc=org 78 | objectclass: top 79 | objectclass: person 80 | objectclass: organizationalPerson 81 | objectclass: inetOrgPerson 82 | cn: slash/guy 83 | sn: Slash 84 | uid: slashguy 85 | userPassword: slashguyspassword 86 | 87 | dn: cn=quote\"guy,ou=\"quoted people\",dc=springframework,dc=org 88 | objectclass: top 89 | objectclass: person 90 | objectclass: organizationalPerson 91 | objectclass: inetOrgPerson 92 | cn: quote\"guy 93 | sn: Quote 94 | uid: quoteguy 95 | userPassword: quoteguyspassword 96 | 97 | dn: uid=space cadet,ou=space cadets,dc=springframework,dc=org 98 | objectclass: top 99 | objectclass: person 100 | objectclass: organizationalPerson 101 | objectclass: inetOrgPerson 102 | cn: Space Cadet 103 | sn: Cadet 104 | uid: space cadet 105 | userPassword: spacecadetspassword 106 | 107 | dn: cn=developers,ou=groups,dc=springframework,dc=org 108 | objectclass: top 109 | objectclass: groupOfUniqueNames 110 | cn: developers 111 | ou: developer 112 | uniqueMember: uid=ben,ou=people,dc=springframework,dc=org 113 | uniqueMember: uid=bob,ou=people,dc=springframework,dc=org 114 | 115 | dn: cn=managers,ou=groups,dc=springframework,dc=org 116 | objectclass: top 117 | objectclass: groupOfUniqueNames 118 | cn: managers 119 | ou: manager 120 | uniqueMember: uid=ben,ou=people,dc=springframework,dc=org 121 | uniqueMember: cn=mouse\, jerry,ou=people,dc=springframework,dc=org 122 | 123 | dn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=org 124 | objectclass: top 125 | objectclass: groupOfUniqueNames 126 | cn: submanagers 127 | ou: submanager 128 | uniqueMember: uid=ben,ou=people,dc=springframework,dc=org 129 | -------------------------------------------------------------------------------- /authentication-provider/src/test/java/livelessons/custom/AtlassianCrowdAuthenticationProviderTest.java: -------------------------------------------------------------------------------- 1 | package livelessons.custom; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.springframework.security.authentication.BadCredentialsException; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.authentication.jaas.JaasAuthenticationToken; 8 | import org.springframework.security.core.Authentication; 9 | 10 | public class AtlassianCrowdAuthenticationProviderTest { 11 | 12 | private final String username = "rob"; 13 | 14 | private final String password = "b0r"; 15 | 16 | private final AtlassianCrowdAuthenticationProvider provider = new AtlassianCrowdAuthenticationProvider( 17 | this.username, this.password); 18 | 19 | @Test 20 | public void authenticateSuccess() { 21 | 22 | UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( 23 | username, password); 24 | Authentication authenticate = this.provider.authenticate(token); 25 | Assert.assertTrue("the authentication should be valid", 26 | authenticate.isAuthenticated()); 27 | } 28 | 29 | @Test(expected = BadCredentialsException.class) 30 | public void authenticateFail() { 31 | UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( 32 | "WR0NG", "N0P3"); 33 | this.provider.authenticate(token); 34 | Assert.fail("this should fail"); 35 | } 36 | 37 | @Test 38 | public void supports() { 39 | Assert.assertTrue( 40 | this.provider.supports(UsernamePasswordAuthenticationToken.class)); 41 | Assert.assertTrue(this.provider.supports(JaasAuthenticationToken.class)); 42 | Assert.assertFalse(this.provider.supports(RuntimeException.class)); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /authentication-provider/src/test/java/livelessons/custom/AuthenticationProviderApplicationTest.java: -------------------------------------------------------------------------------- 1 | package livelessons.custom; 2 | 3 | import org.apache.commons.logging.Log; 4 | import org.apache.commons.logging.LogFactory; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.BeansException; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.beans.factory.config.BeanPostProcessor; 11 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.Configuration; 15 | import org.springframework.http.HttpHeaders; 16 | import org.springframework.test.context.junit4.SpringRunner; 17 | import org.springframework.test.web.servlet.MockMvc; 18 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 19 | import org.springframework.test.web.servlet.result.MockMvcResultMatchers; 20 | 21 | import java.nio.charset.StandardCharsets; 22 | import java.util.Base64; 23 | 24 | @SpringBootTest(classes = { AuthenticationProviderApplication.class, 25 | AuthenticationProviderApplicationTest.Replacer.class }) 26 | @RunWith(SpringRunner.class) 27 | @AutoConfigureMockMvc 28 | public class AuthenticationProviderApplicationTest { 29 | 30 | private static final String USER = "USER", PW = "PW"; 31 | 32 | @Configuration 33 | public static class Replacer { 34 | 35 | @Bean 36 | BeanPostProcessor beanPostProcessor() { 37 | return new BeanPostProcessor() { 38 | 39 | @Override 40 | public Object postProcessBeforeInitialization(Object bean, 41 | String beanName) throws BeansException { 42 | if (bean instanceof AtlassianCrowdAuthenticationProvider) { 43 | // want to replace it with one that we control for the test. 44 | return new AtlassianCrowdAuthenticationProvider(USER, PW); 45 | } 46 | else { 47 | return bean; 48 | } 49 | } 50 | 51 | @Override 52 | public Object postProcessAfterInitialization(Object bean, String beanName) 53 | throws BeansException { 54 | return bean; 55 | } 56 | }; 57 | } 58 | 59 | } 60 | 61 | @Autowired 62 | private MockMvc mockMvc; 63 | 64 | private final Log log = LogFactory.getLog(getClass()); 65 | 66 | @Autowired 67 | public void config(AtlassianCrowdAuthenticationProvider ap) throws Exception { 68 | this.log.info(String.format( 69 | "attempting to authenticate using username '%s' and password '%s'", 70 | ap.hardcodedUsername, ap.hardcodedPassword)); 71 | } 72 | 73 | @Test 74 | public void login() throws Exception { 75 | 76 | String name = USER, pw = PW; 77 | this.mockMvc 78 | .perform(MockMvcRequestBuilders.get("/greet").header( 79 | HttpHeaders.AUTHORIZATION, basicAuthorizationHeader(name, pw))) 80 | .andExpect(MockMvcResultMatchers.status().isOk()).andExpect(result -> { 81 | String body = result.getResponse().getContentAsString(); 82 | Assert.assertEquals(body, "hello, " + name + "!"); 83 | }); 84 | } 85 | 86 | private String basicAuthorizationHeader(String u, String p) { 87 | String auth = u + ':' + p; 88 | byte[] encoded = Base64.getEncoder() 89 | .encode(auth.getBytes(StandardCharsets.ISO_8859_1)); 90 | return "Basic " + new String(encoded); 91 | } 92 | 93 | } -------------------------------------------------------------------------------- /authentication-provider/src/test/java/livelessons/ldap/LdapAuthenticationApplicationTest.java: -------------------------------------------------------------------------------- 1 | package livelessons.ldap; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.http.HttpHeaders; 10 | import org.springframework.test.context.ActiveProfiles; 11 | import org.springframework.test.context.junit4.SpringRunner; 12 | import org.springframework.test.web.servlet.MockMvc; 13 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 14 | import org.springframework.test.web.servlet.result.MockMvcResultMatchers; 15 | 16 | import java.nio.charset.StandardCharsets; 17 | import java.util.Base64; 18 | 19 | @SpringBootTest(classes = { LdapAuthenticationApplication.class }) 20 | @RunWith(SpringRunner.class) 21 | @AutoConfigureMockMvc 22 | @ActiveProfiles("ldap") 23 | public class LdapAuthenticationApplicationTest { 24 | 25 | @Autowired 26 | private MockMvc mockMvc; 27 | 28 | @Test 29 | public void login() throws Exception { 30 | String name = "ben", pw = "benspassword"; 31 | this.mockMvc 32 | .perform(MockMvcRequestBuilders.get("/greet").header( 33 | HttpHeaders.AUTHORIZATION, basicAuthorizationHeader(name, pw))) 34 | .andExpect(MockMvcResultMatchers.status().isOk()).andExpect(result -> { 35 | String body = result.getResponse().getContentAsString(); 36 | Assert.assertEquals(body, "hello, " + name + "!"); 37 | }); 38 | } 39 | 40 | private String basicAuthorizationHeader(String u, String p) { 41 | String auth = u + ':' + p; 42 | byte[] encoded = Base64.getEncoder() 43 | .encode(auth.getBytes(StandardCharsets.ISO_8859_1)); 44 | return "Basic " + new String(encoded); 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /login/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | login 7 | jar 8 | 9 | livelessons 10 | authentication 11 | 0.0.1-SNAPSHOT 12 | .. 13 | 14 | 15 | 16 | com.h2database 17 | h2 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter 22 | 23 | 24 | org.projectlombok 25 | lombok 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-security 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-thymeleaf 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-actuator 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-web 42 | 43 | 44 | nz.net.ultraq.thymeleaf 45 | thymeleaf-layout-dialect 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-devtools 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-test 55 | test 56 | 57 | 58 | org.springframework.security 59 | spring-security-test 60 | test 61 | 62 | 63 | org.seleniumhq.selenium 64 | htmlunit-driver 65 | test 66 | 67 | 68 | org.seleniumhq.selenium 69 | selenium-support 70 | test 71 | 72 | 77 | 78 | 79 | 80 | 81 | 82 | org.springframework.boot 83 | spring-boot-maven-plugin 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /login/src/main/java/livelessons/LoginApplication.java: -------------------------------------------------------------------------------- 1 | package livelessons; 2 | 3 | import org.apache.commons.logging.Log; 4 | import org.apache.commons.logging.LogFactory; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 8 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.web.bind.annotation.ControllerAdvice; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.ModelAttribute; 14 | 15 | import java.security.Principal; 16 | 17 | @SpringBootApplication 18 | public class LoginApplication { 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(LoginApplication.class, args); 22 | } 23 | 24 | } 25 | 26 | @ControllerAdvice 27 | class SecurityControllerAdvice { 28 | 29 | @ModelAttribute("currentUser") 30 | Principal currentUser(Principal principal) { 31 | return principal; 32 | } 33 | 34 | } 35 | 36 | @Controller 37 | class LoginController { 38 | 39 | @GetMapping("/") 40 | String index() { 41 | return "hidden"; 42 | } 43 | 44 | @GetMapping("/logout-success") 45 | String logout() { 46 | return "logout"; 47 | } 48 | 49 | @GetMapping("/login") 50 | String login() { 51 | return "login"; 52 | } 53 | 54 | } 55 | 56 | @EnableWebSecurity 57 | class SecurityConfig extends WebSecurityConfigurerAdapter { 58 | 59 | @Override 60 | protected void configure(HttpSecurity http) throws Exception { 61 | http.authorizeRequests().anyRequest().authenticated(); 62 | http.logout().logoutUrl("/logout").logoutSuccessUrl("/logout-success") 63 | .permitAll(); 64 | http.formLogin().loginPage("/login").permitAll(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /login/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # expose the Actuator endpoints 2 | management.endpoints.web.exposure.include=* 3 | management.endpoint.health.show-details=always 4 | 5 | # for Spring Security 6 | spring.security.user.name=user 7 | spring.security.user.password=password -------------------------------------------------------------------------------- /login/src/main/resources/templates/hidden.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Yahaha! You Found Me! 4 | 5 |
6 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /login/src/main/resources/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Spring Security Livelessons 7 | 8 | 9 |
10 | 11 |
12 | 13 |
14 |
15 |
16 |
17 | 18 | -------------------------------------------------------------------------------- /login/src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Please Log In 7 | 8 | 9 |
10 | 11 |

Please Log In

12 | 13 |
14 |
Invalid username and password.
15 |
You have been logged out.
16 |

17 | 18 | 19 |

20 |

21 | 22 | 23 |

24 | 25 |
26 |
27 | 28 | -------------------------------------------------------------------------------- /login/src/main/resources/templates/logout.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Goodbye! 7 | 8 | 9 |
10 |

..Don't Forget to Write

11 |
12 | 13 | -------------------------------------------------------------------------------- /login/src/test/java/livelessons/LoginApplicationTests.java: -------------------------------------------------------------------------------- 1 | package livelessons; 2 | 3 | import livelessons.webdriver.HiddenPage; 4 | import livelessons.webdriver.LoginPage; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.openqa.selenium.WebDriver; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.autoconfigure.security.SecurityProperties; 10 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | 14 | @SpringBootTest 15 | @AutoConfigureMockMvc 16 | @RunWith(SpringRunner.class) 17 | public class LoginApplicationTests { 18 | 19 | @Autowired 20 | private WebDriver driver; 21 | 22 | @Autowired 23 | private SecurityProperties securityProperties; 24 | 25 | @Test 26 | public void requiresLogin() { 27 | HiddenPage.to(this.driver, LoginPage.class).assertAt(); 28 | } 29 | 30 | @Test 31 | public void loginFailure() { 32 | HiddenPage.to(this.driver, LoginPage.class).form().username("user") 33 | .password("invalid").login(LoginPage.class).assertAt(); 34 | } 35 | 36 | @Test 37 | public void loginSuccess() { 38 | HiddenPage.to(this.driver, LoginPage.class).form() 39 | .username(this.securityProperties.getUser().getName()) 40 | .password(this.securityProperties.getUser().getPassword()) 41 | .login(HiddenPage.class).assertAt(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /login/src/test/java/livelessons/webdriver/HiddenPage.java: -------------------------------------------------------------------------------- 1 | package livelessons.webdriver; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.support.PageFactory; 5 | 6 | import static org.assertj.core.api.Assertions.assertThat; 7 | 8 | public class HiddenPage { 9 | 10 | private WebDriver driver; 11 | 12 | public HiddenPage(WebDriver driver) { 13 | this.driver = driver; 14 | } 15 | 16 | public static T to(WebDriver driver, Class page) { 17 | driver.get("http://localhost:8080/"); 18 | return (T) PageFactory.initElements(driver, page); 19 | } 20 | 21 | public void assertAt() { 22 | assertThat(this.driver.getTitle()).endsWith("Yahaha! You Found Me!"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /login/src/test/java/livelessons/webdriver/LoginPage.java: -------------------------------------------------------------------------------- 1 | package livelessons.webdriver; 2 | 3 | import org.openqa.selenium.SearchContext; 4 | import org.openqa.selenium.WebDriver; 5 | import org.openqa.selenium.WebElement; 6 | import org.openqa.selenium.support.FindBy; 7 | import org.openqa.selenium.support.PageFactory; 8 | import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | public class LoginPage { 13 | 14 | private WebDriver driver; 15 | 16 | public LoginPage(WebDriver driver) { 17 | this.driver = driver; 18 | } 19 | 20 | public void assertAt() { 21 | assertThat(this.driver.getTitle()).endsWith("Please Log In"); 22 | } 23 | 24 | public Form form() { 25 | return new Form(this.driver); 26 | } 27 | 28 | public class Form { 29 | 30 | @FindBy(name = "username") 31 | private WebElement username; 32 | 33 | @FindBy(name = "password") 34 | private WebElement password; 35 | 36 | @FindBy(name = "submit") 37 | private WebElement button; 38 | 39 | public Form(SearchContext context) { 40 | PageFactory.initElements(new DefaultElementLocatorFactory(context), this); 41 | } 42 | 43 | public Form username(String username) { 44 | this.username.sendKeys(username); 45 | return this; 46 | } 47 | 48 | public Form password(String password) { 49 | this.password.sendKeys(password); 50 | return this; 51 | } 52 | 53 | public T login(Class page) { 54 | this.button.click(); 55 | return PageFactory.initElements(LoginPage.this.driver, page); 56 | } 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /login/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /password-migration/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /password-migration/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/password-migration/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /password-migration/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /password-migration/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /password-migration/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | password-migration 7 | jar 8 | 9 | 10 | livelessons 11 | authentication 12 | 0.0.1-SNAPSHOT 13 | .. 14 | 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-security 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | 27 | org.projectlombok 28 | lombok 29 | true 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | org.springframework.security 38 | spring-security-test 39 | test 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-maven-plugin 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /password-migration/src/main/java/com/example/passwordmigration/CustomAuthenticationApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.passwordmigration; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | import org.springframework.security.crypto.factory.PasswordEncoderFactories; 8 | import org.springframework.security.crypto.password.DelegatingPasswordEncoder; 9 | import org.springframework.security.crypto.password.MessageDigestPasswordEncoder; 10 | import org.springframework.security.crypto.password.PasswordEncoder; 11 | 12 | import java.util.Arrays; 13 | import java.util.Collection; 14 | import java.util.Collections; 15 | 16 | @SpringBootApplication 17 | public class CustomAuthenticationApplication { 18 | 19 | // @Bean 20 | PasswordEncoder oldPasswordEncoder() { 21 | String md5 = "MD5"; 22 | return new DelegatingPasswordEncoder(md5, 23 | Collections.singletonMap(md5, new MessageDigestPasswordEncoder(md5))); 24 | } 25 | 26 | @Bean 27 | PasswordEncoder passwordEncoder() { 28 | return PasswordEncoderFactories.createDelegatingPasswordEncoder(); 29 | } 30 | 31 | @Bean 32 | CustomUserDetailsService customUserDetailsService() { 33 | Collection users = Arrays.asList( 34 | new CustomUserDetails("jlong", oldPasswordEncoder().encode("password"), 35 | true, "USER"), 36 | new CustomUserDetails("rwinch", oldPasswordEncoder().encode("password"), 37 | true, "USER", "ADMIN")); 38 | return new CustomUserDetailsService(users); 39 | } 40 | 41 | public static void main(String[] args) { 42 | SpringApplication.run(CustomAuthenticationApplication.class, args); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /password-migration/src/main/java/com/example/passwordmigration/CustomSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.passwordmigration; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 6 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 7 | 8 | @Configuration 9 | @EnableWebSecurity 10 | class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter { 11 | 12 | @Override 13 | protected void configure(HttpSecurity http) throws Exception { 14 | http.httpBasic(); 15 | http.authorizeRequests().anyRequest().authenticated(); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /password-migration/src/main/java/com/example/passwordmigration/CustomUserDetails.java: -------------------------------------------------------------------------------- 1 | package com.example.passwordmigration; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 5 | import org.springframework.security.core.userdetails.UserDetails; 6 | 7 | import java.util.Collection; 8 | import java.util.Set; 9 | import java.util.stream.Collectors; 10 | import java.util.stream.Stream; 11 | 12 | class CustomUserDetails implements UserDetails { 13 | 14 | private final Set authorities; 15 | 16 | private final String username, password; 17 | 18 | private final boolean active; 19 | 20 | CustomUserDetails(String username, String password, boolean active, 21 | String... authorities) { 22 | this.username = username; 23 | this.password = password; 24 | this.active = active; 25 | this.authorities = Stream.of(authorities).map(SimpleGrantedAuthority::new) 26 | .collect(Collectors.toSet()); 27 | } 28 | 29 | @Override 30 | public Collection getAuthorities() { 31 | return this.authorities; 32 | } 33 | 34 | @Override 35 | public String getPassword() { 36 | return this.password; 37 | } 38 | 39 | @Override 40 | public String getUsername() { 41 | return this.username; 42 | } 43 | 44 | @Override 45 | public boolean isAccountNonExpired() { 46 | return this.active; 47 | } 48 | 49 | @Override 50 | public boolean isAccountNonLocked() { 51 | return this.active; 52 | } 53 | 54 | @Override 55 | public boolean isCredentialsNonExpired() { 56 | return this.active; 57 | } 58 | 59 | @Override 60 | public boolean isEnabled() { 61 | return this.active; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /password-migration/src/main/java/com/example/passwordmigration/CustomUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.example.passwordmigration; 2 | 3 | import lombok.extern.log4j.Log4j2; 4 | import org.springframework.security.core.GrantedAuthority; 5 | import org.springframework.security.core.userdetails.UserDetails; 6 | import org.springframework.security.core.userdetails.UserDetailsPasswordService; 7 | import org.springframework.security.core.userdetails.UserDetailsService; 8 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 9 | 10 | import java.util.Collection; 11 | import java.util.Map; 12 | import java.util.concurrent.ConcurrentHashMap; 13 | 14 | @Log4j2 15 | class CustomUserDetailsService implements UserDetailsService, UserDetailsPasswordService { 16 | 17 | private final Map users = new ConcurrentHashMap<>(); 18 | 19 | public CustomUserDetailsService(Collection seedUsers) { 20 | seedUsers.forEach(user -> this.users.put(user.getUsername(), user)); 21 | this.users.forEach((k, v) -> log.info(k + "=" + v.getPassword())); 22 | } 23 | 24 | @Override 25 | public UserDetails loadUserByUsername(String username) 26 | throws UsernameNotFoundException { 27 | if (this.users.containsKey(username)) { 28 | return this.users.get(username); 29 | } 30 | throw new UsernameNotFoundException(String.format("couldn't find %s!", username)); 31 | } 32 | 33 | @Override 34 | public UserDetails updatePassword(UserDetails user, String newPassword) { 35 | log.info("prompted to updated password for user " + user.getUsername() + " to " 36 | + newPassword); 37 | 38 | this.users.put(user.getUsername(), 39 | new CustomUserDetails(user.getUsername(), newPassword, user.isEnabled(), 40 | user.getAuthorities().stream().map(GrantedAuthority::getAuthority) 41 | .toArray(String[]::new))); 42 | 43 | return this.loadUserByUsername(user.getUsername()); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /password-migration/src/main/java/com/example/passwordmigration/GreetingRestController.java: -------------------------------------------------------------------------------- 1 | package com.example.passwordmigration; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | import java.security.Principal; 7 | 8 | @RestController 9 | class GreetingRestController { 10 | 11 | @GetMapping("/greeting") 12 | String greet(Principal p) { 13 | return "greetings, " + p.getName() + "!"; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /password-migration/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/password-migration/src/main/resources/application.properties -------------------------------------------------------------------------------- /password-migration/src/test/java/com/example/passwordmigration/PasswordMigrationApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.passwordmigration; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class PasswordMigrationApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | livelessons 7 | authentication 8 | 0.0.1-SNAPSHOT 9 | pom 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 2.1.0.RC1 14 | 15 | 16 | 17 | 0.0.6 18 | 19 | 20 | 21 | login 22 | user-details 23 | password-migration 24 | xauth 25 | xauth-app 26 | authentication-provider 27 | 28 | 29 | 30 | 31 | org.webjars 32 | bootstrap 33 | 4.0.0-alpha.6-1 34 | 35 | 36 | org.webjars 37 | tether 38 | 1.4.0 39 | 40 | 41 | org.webjars 42 | jquery 43 | 3.1.1 44 | 45 | 46 | org.seleniumhq.selenium 47 | htmlunit-driver 48 | ${selenium-htmlunit.version} 49 | test 50 | 51 | 52 | org.seleniumhq.selenium 53 | selenium-support 54 | ${selenium.version} 55 | test 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | spring-snapshots 70 | Spring Snapshots 71 | https://repo.spring.io/snapshot 72 | 73 | true 74 | 75 | 76 | 77 | spring-milestones 78 | Spring Milestones 79 | https://repo.spring.io/milestone 80 | 81 | false 82 | 83 | 84 | 85 | 86 | 87 | 88 | spring-snapshots 89 | Spring Snapshots 90 | https://repo.spring.io/snapshot 91 | 92 | true 93 | 94 | 95 | 96 | spring-milestones 97 | Spring Milestones 98 | https://repo.spring.io/milestone 99 | 100 | false 101 | 102 | 103 | 104 | 105 | 106 | 107 | io.spring.javaformat 108 | spring-javaformat-maven-plugin 109 | ${spring-javaformat-maven-plugin.version} 110 | 111 | 112 | validate 113 | true 114 | 115 | validate 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /studio/auditing/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /studio/auditing/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/studio/auditing/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /studio/auditing/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /studio/auditing/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /studio/auditing/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | custom-authentication 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | custom-authentication 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.1.0.BUILD-SNAPSHOT 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-actuator 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-security 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 40 | 41 | 42 | org.projectlombok 43 | lombok 44 | true 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | org.springframework.security 53 | spring-security-test 54 | test 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-maven-plugin 63 | 64 | 65 | 66 | 67 | 68 | 69 | spring-snapshots 70 | Spring Snapshots 71 | https://repo.spring.io/snapshot 72 | 73 | true 74 | 75 | 76 | 77 | spring-milestones 78 | Spring Milestones 79 | https://repo.spring.io/milestone 80 | 81 | false 82 | 83 | 84 | 85 | 86 | 87 | 88 | spring-snapshots 89 | Spring Snapshots 90 | https://repo.spring.io/snapshot 91 | 92 | true 93 | 94 | 95 | 96 | spring-milestones 97 | Spring Milestones 98 | https://repo.spring.io/milestone 99 | 100 | false 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /studio/auditing/src/main/java/com/example/customauthentication/CustomAuthenticationApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.customauthentication; 2 | 3 | import lombok.extern.log4j.Log4j2; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 11 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 12 | import org.springframework.security.core.GrantedAuthority; 13 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 14 | import org.springframework.security.core.userdetails.UserDetails; 15 | import org.springframework.security.core.userdetails.UserDetailsPasswordService; 16 | import org.springframework.security.core.userdetails.UserDetailsService; 17 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 18 | import org.springframework.security.crypto.factory.PasswordEncoderFactories; 19 | import org.springframework.security.crypto.password.DelegatingPasswordEncoder; 20 | import org.springframework.security.crypto.password.MessageDigestPasswordEncoder; 21 | import org.springframework.security.crypto.password.PasswordEncoder; 22 | import org.springframework.web.bind.annotation.GetMapping; 23 | import org.springframework.web.bind.annotation.RestController; 24 | 25 | import java.security.Principal; 26 | import java.util.*; 27 | import java.util.concurrent.ConcurrentHashMap; 28 | import java.util.stream.Collectors; 29 | import java.util.stream.Stream; 30 | 31 | @SpringBootApplication 32 | public class CustomAuthenticationApplication { 33 | 34 | // @Bean 35 | PasswordEncoder oldPasswordEncoder() { 36 | String md5 = "MD5"; 37 | return new DelegatingPasswordEncoder(md5, 38 | Collections.singletonMap(md5, new MessageDigestPasswordEncoder(md5))); 39 | } 40 | 41 | @Bean 42 | PasswordEncoder passwordEncoder() { 43 | return PasswordEncoderFactories.createDelegatingPasswordEncoder(); 44 | } 45 | 46 | @Bean 47 | CustomUserDetailsService customUserDetailsService() { 48 | Collection users = Arrays.asList( 49 | new CustomUserDetails("jlong", oldPasswordEncoder().encode("password"), true, "USER"), 50 | new CustomUserDetails("rwinch", oldPasswordEncoder().encode("password"), true, "USER", "ADMIN") 51 | ); 52 | return new CustomUserDetailsService(users); 53 | } 54 | 55 | public static void main(String[] args) { 56 | SpringApplication.run(CustomAuthenticationApplication.class, args); 57 | } 58 | } 59 | 60 | @RestController 61 | class GreetingRestController { 62 | 63 | @GetMapping("/greeting") 64 | String greet(Principal p) { 65 | return "greetings, " + p.getName() + "!"; 66 | } 67 | } 68 | 69 | @Configuration 70 | @EnableWebSecurity 71 | class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter { 72 | 73 | @Override 74 | protected void configure(HttpSecurity http) throws Exception { 75 | http.httpBasic(); 76 | http.authorizeRequests().anyRequest().authenticated(); 77 | } 78 | } 79 | 80 | @Log4j2 81 | class CustomUserDetailsService implements UserDetailsService, 82 | UserDetailsPasswordService { 83 | 84 | private final Map users = new ConcurrentHashMap<>(); 85 | 86 | public CustomUserDetailsService(Collection seedUsers) { 87 | seedUsers.forEach(user -> this.users.put(user.getUsername(), user)); 88 | this.users.forEach((k, v) -> log.info(k + "=" + v.getPassword())); 89 | } 90 | 91 | @Override 92 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 93 | if (this.users.containsKey(username)) { 94 | return this.users.get(username); 95 | } 96 | throw new UsernameNotFoundException(String.format("couldn't find %s!", username)); 97 | } 98 | 99 | @Override 100 | public UserDetails updatePassword(UserDetails user, String newPassword) { 101 | log.info("prompted to updated password for user " + user.getUsername() + " to " + newPassword); 102 | 103 | this.users.put(user.getUsername(), new CustomUserDetails( 104 | user.getUsername(), 105 | newPassword, 106 | user.isEnabled(), 107 | user.getAuthorities().stream().map(GrantedAuthority::getAuthority).toArray(String[]::new) 108 | )); 109 | 110 | return this.loadUserByUsername(user.getUsername()); 111 | } 112 | } 113 | 114 | 115 | class CustomUserDetails implements UserDetails { 116 | 117 | private final Set authorities; 118 | private final String username, password; 119 | private final boolean active; 120 | 121 | public CustomUserDetails(String username, String password, boolean active, String... authorities) { 122 | this.username = username; 123 | this.password = password; 124 | this.active = active; 125 | this.authorities = Stream 126 | .of(authorities) 127 | .map(SimpleGrantedAuthority::new) 128 | .collect(Collectors.toSet()); 129 | } 130 | 131 | @Override 132 | public Collection getAuthorities() { 133 | return this.authorities; 134 | } 135 | 136 | @Override 137 | public String getPassword() { 138 | return this.password; 139 | } 140 | 141 | @Override 142 | public String getUsername() { 143 | return this.username; 144 | } 145 | 146 | @Override 147 | public boolean isAccountNonExpired() { 148 | return this.active; 149 | } 150 | 151 | @Override 152 | public boolean isAccountNonLocked() { 153 | return this.active; 154 | } 155 | 156 | @Override 157 | public boolean isCredentialsNonExpired() { 158 | return this.active; 159 | } 160 | 161 | @Override 162 | public boolean isEnabled() { 163 | return this.active; 164 | } 165 | } -------------------------------------------------------------------------------- /studio/auditing/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | management.endpoints.web.exposure.include=* 2 | -------------------------------------------------------------------------------- /studio/auditing/src/test/java/com/example/customauthentication/CustomAuthenticationApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.customauthentication; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CustomAuthenticationApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /studio/custom-authentication/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /studio/custom-authentication/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/studio/custom-authentication/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /studio/custom-authentication/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /studio/custom-authentication/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /studio/custom-authentication/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | custom-authentication 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | custom-authentication 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.1.0.BUILD-SNAPSHOT 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-actuator 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-security 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 40 | 41 | 42 | org.projectlombok 43 | lombok 44 | true 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | org.springframework.security 53 | spring-security-test 54 | test 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-maven-plugin 63 | 64 | 65 | 66 | 67 | 68 | 69 | spring-snapshots 70 | Spring Snapshots 71 | https://repo.spring.io/snapshot 72 | 73 | true 74 | 75 | 76 | 77 | spring-milestones 78 | Spring Milestones 79 | https://repo.spring.io/milestone 80 | 81 | false 82 | 83 | 84 | 85 | 86 | 87 | 88 | spring-snapshots 89 | Spring Snapshots 90 | https://repo.spring.io/snapshot 91 | 92 | true 93 | 94 | 95 | 96 | spring-milestones 97 | Spring Milestones 98 | https://repo.spring.io/milestone 99 | 100 | false 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /studio/custom-authentication/src/main/java/com/example/customauthentication/CustomAuthenticationApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.customauthentication; 2 | 3 | import lombok.extern.log4j.Log4j2; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 11 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 12 | import org.springframework.security.core.GrantedAuthority; 13 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 14 | import org.springframework.security.core.userdetails.UserDetails; 15 | import org.springframework.security.core.userdetails.UserDetailsPasswordService; 16 | import org.springframework.security.core.userdetails.UserDetailsService; 17 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 18 | import org.springframework.security.crypto.factory.PasswordEncoderFactories; 19 | import org.springframework.security.crypto.password.DelegatingPasswordEncoder; 20 | import org.springframework.security.crypto.password.MessageDigestPasswordEncoder; 21 | import org.springframework.security.crypto.password.PasswordEncoder; 22 | import org.springframework.web.bind.annotation.GetMapping; 23 | import org.springframework.web.bind.annotation.RestController; 24 | 25 | import java.security.Principal; 26 | import java.util.*; 27 | import java.util.concurrent.ConcurrentHashMap; 28 | import java.util.stream.Collectors; 29 | import java.util.stream.Stream; 30 | 31 | @SpringBootApplication 32 | public class CustomAuthenticationApplication { 33 | 34 | // @Bean 35 | PasswordEncoder oldPasswordEncoder() { 36 | String md5 = "MD5"; 37 | return new DelegatingPasswordEncoder(md5, 38 | Collections.singletonMap(md5, new MessageDigestPasswordEncoder(md5))); 39 | } 40 | 41 | @Bean 42 | PasswordEncoder passwordEncoder() { 43 | return PasswordEncoderFactories.createDelegatingPasswordEncoder(); 44 | } 45 | 46 | @Bean 47 | CustomUserDetailsService customUserDetailsService() { 48 | Collection users = Arrays.asList( 49 | new CustomUserDetails("jlong", oldPasswordEncoder().encode("password"), true, "USER"), 50 | new CustomUserDetails("rwinch", oldPasswordEncoder().encode("password"), true, "USER", "ADMIN") 51 | ); 52 | return new CustomUserDetailsService(users); 53 | } 54 | 55 | public static void main(String[] args) { 56 | SpringApplication.run(CustomAuthenticationApplication.class, args); 57 | } 58 | } 59 | 60 | @RestController 61 | class GreetingRestController { 62 | 63 | @GetMapping("/greeting") 64 | String greet(Principal p) { 65 | return "greetings, " + p.getName() + "!"; 66 | } 67 | } 68 | 69 | @Configuration 70 | @EnableWebSecurity 71 | class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter { 72 | 73 | @Override 74 | protected void configure(HttpSecurity http) throws Exception { 75 | http.httpBasic(); 76 | http.authorizeRequests().anyRequest().authenticated(); 77 | } 78 | } 79 | 80 | @Log4j2 81 | class CustomUserDetailsService implements UserDetailsService, 82 | UserDetailsPasswordService { 83 | 84 | private final Map users = new ConcurrentHashMap<>(); 85 | 86 | public CustomUserDetailsService(Collection seedUsers) { 87 | seedUsers.forEach(user -> this.users.put(user.getUsername(), user)); 88 | this.users.forEach((k, v) -> log.info(k + "=" + v.getPassword())); 89 | } 90 | 91 | @Override 92 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 93 | if (this.users.containsKey(username)) { 94 | return this.users.get(username); 95 | } 96 | throw new UsernameNotFoundException(String.format("couldn't find %s!", username)); 97 | } 98 | 99 | @Override 100 | public UserDetails updatePassword(UserDetails user, String newPassword) { 101 | log.info("prompted to updated password for user " + user.getUsername() + " to " + newPassword); 102 | 103 | this.users.put(user.getUsername(), new CustomUserDetails( 104 | user.getUsername(), 105 | newPassword, 106 | user.isEnabled(), 107 | user.getAuthorities().stream().map(GrantedAuthority::getAuthority).toArray(String[]::new) 108 | )); 109 | 110 | return this.loadUserByUsername(user.getUsername()); 111 | } 112 | } 113 | 114 | 115 | class CustomUserDetails implements UserDetails { 116 | 117 | private final Set authorities; 118 | private final String username, password; 119 | private final boolean active; 120 | 121 | public CustomUserDetails(String username, String password, boolean active, String... authorities) { 122 | this.username = username; 123 | this.password = password; 124 | this.active = active; 125 | this.authorities = Stream 126 | .of(authorities) 127 | .map(SimpleGrantedAuthority::new) 128 | .collect(Collectors.toSet()); 129 | } 130 | 131 | @Override 132 | public Collection getAuthorities() { 133 | return this.authorities; 134 | } 135 | 136 | @Override 137 | public String getPassword() { 138 | return this.password; 139 | } 140 | 141 | @Override 142 | public String getUsername() { 143 | return this.username; 144 | } 145 | 146 | @Override 147 | public boolean isAccountNonExpired() { 148 | return this.active; 149 | } 150 | 151 | @Override 152 | public boolean isAccountNonLocked() { 153 | return this.active; 154 | } 155 | 156 | @Override 157 | public boolean isCredentialsNonExpired() { 158 | return this.active; 159 | } 160 | 161 | @Override 162 | public boolean isEnabled() { 163 | return this.active; 164 | } 165 | } -------------------------------------------------------------------------------- /studio/custom-authentication/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | management.endpoints.web.exposure.include=* 2 | -------------------------------------------------------------------------------- /studio/custom-authentication/src/test/java/com/example/customauthentication/CustomAuthenticationApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.customauthentication; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CustomAuthenticationApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /studio/inmemory/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /studio/inmemory/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/studio/inmemory/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /studio/inmemory/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /studio/inmemory/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /studio/inmemory/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | inmemory 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | inmemory 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-security 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-web 35 | 36 | 37 | 38 | org.projectlombok 39 | lombok 40 | true 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-test 45 | test 46 | 47 | 48 | org.springframework.security 49 | spring-security-test 50 | test 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-maven-plugin 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /studio/inmemory/src/main/java/com/example/inmemory/InmemoryApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.inmemory; 2 | 3 | import org.springframework.beans.factory.InitializingBean; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 11 | import org.springframework.security.core.userdetails.User; 12 | import org.springframework.security.core.userdetails.UserDetails; 13 | import org.springframework.security.provisioning.InMemoryUserDetailsManager; 14 | import org.springframework.security.provisioning.UserDetailsManager; 15 | import org.springframework.web.bind.annotation.GetMapping; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | import java.security.Principal; 19 | 20 | @SpringBootApplication 21 | public class InmemoryApplication { 22 | 23 | @Bean 24 | UserDetailsManager memory() { 25 | return new InMemoryUserDetailsManager(); 26 | } 27 | 28 | @Bean 29 | InitializingBean initializer(UserDetailsManager manager) { 30 | return () -> { 31 | 32 | UserDetails josh = User.withDefaultPasswordEncoder().username("jlong").password("password").roles("USER").build(); 33 | manager.createUser(josh); 34 | 35 | UserDetails rob = User.withUserDetails(josh).username("rwinch").build(); 36 | manager.createUser(rob); 37 | }; 38 | } 39 | 40 | 41 | public static void main(String[] args) { 42 | SpringApplication.run(InmemoryApplication.class, args); 43 | } 44 | } 45 | 46 | 47 | @RestController 48 | class GreetingsRestController { 49 | 50 | @GetMapping("/greeting") 51 | String greeting(Principal principal) { 52 | return "hello, " + principal.getName() + "!"; 53 | } 54 | } 55 | 56 | @Configuration 57 | @EnableWebSecurity 58 | class SecurityConfiguration extends WebSecurityConfigurerAdapter { 59 | 60 | @Override 61 | protected void configure(HttpSecurity http) throws Exception { 62 | 63 | http 64 | .httpBasic(); 65 | 66 | http 67 | .authorizeRequests().anyRequest().authenticated(); 68 | } 69 | } -------------------------------------------------------------------------------- /studio/inmemory/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/studio/inmemory/src/main/resources/application.properties -------------------------------------------------------------------------------- /studio/inmemory/src/test/java/com/example/inmemory/InmemoryApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.inmemory; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class InmemoryApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /studio/jdbc/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /studio/jdbc/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/studio/jdbc/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /studio/jdbc/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /studio/jdbc/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /studio/jdbc/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /studio/jdbc/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | jdbc 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | jdbc 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-security 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-web 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-jdbc 39 | 40 | 41 | 42 | com.h2database 43 | h2 44 | runtime 45 | 46 | 47 | org.projectlombok 48 | lombok 49 | true 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-test 54 | test 55 | 56 | 57 | org.springframework.security 58 | spring-security-test 59 | test 60 | 61 | 62 | 63 | 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-maven-plugin 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /studio/jdbc/src/main/java/com/example/jdbc/JdbcApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.jdbc; 2 | 3 | import org.springframework.beans.factory.InitializingBean; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 11 | import org.springframework.security.core.userdetails.User; 12 | import org.springframework.security.core.userdetails.UserDetails; 13 | import org.springframework.security.provisioning.JdbcUserDetailsManager; 14 | import org.springframework.security.provisioning.UserDetailsManager; 15 | import org.springframework.web.bind.annotation.GetMapping; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | import javax.sql.DataSource; 19 | import java.security.Principal; 20 | 21 | @SpringBootApplication 22 | public class JdbcApplication { 23 | 24 | @Bean 25 | UserDetailsManager memory(DataSource ds) { 26 | JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager(); 27 | jdbcUserDetailsManager.setDataSource(ds); 28 | return jdbcUserDetailsManager; 29 | } 30 | 31 | @Bean 32 | InitializingBean initializer(UserDetailsManager manager) { 33 | return () -> { 34 | 35 | UserDetails josh = User.withDefaultPasswordEncoder().username("jlong").password("password").roles("USER").build(); 36 | manager.createUser(josh); 37 | 38 | UserDetails rob = User.withUserDetails(josh).username("rwinch").build(); 39 | manager.createUser(rob); 40 | }; 41 | } 42 | 43 | 44 | public static void main(String[] args) { 45 | SpringApplication.run(JdbcApplication.class, args); 46 | } 47 | } 48 | 49 | 50 | @RestController 51 | class GreetingsRestController { 52 | 53 | @GetMapping("/greeting") 54 | String greeting(Principal principal) { 55 | return "hello, " + principal.getName() + "!"; 56 | } 57 | } 58 | 59 | @Configuration 60 | @EnableWebSecurity 61 | class SecurityConfiguration extends WebSecurityConfigurerAdapter { 62 | 63 | @Override 64 | protected void configure(HttpSecurity http) throws Exception { 65 | 66 | http 67 | .httpBasic(); 68 | 69 | http 70 | .authorizeRequests().anyRequest().authenticated(); 71 | } 72 | } -------------------------------------------------------------------------------- /studio/jdbc/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/studio/jdbc/src/main/resources/application.properties -------------------------------------------------------------------------------- /studio/jdbc/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | drop table if exists users; 2 | 3 | create table users ( 4 | username varchar(50) not null primary key, 5 | password varchar(500) not null, 6 | enabled boolean not null 7 | ); 8 | 9 | drop table if exists authorities; 10 | create table authorities ( 11 | username varchar(255) not null, 12 | authority varchar(50) not null, 13 | constraint fk_authorities_users foreign key (username) references users (username) 14 | ); 15 | 16 | create unique index ix_auth_username 17 | on authorities (username, authority); -------------------------------------------------------------------------------- /studio/jdbc/src/test/java/com/example/jdbc/JdbcApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.jdbc; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class JdbcApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /studio/ldap/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /studio/ldap/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/studio/ldap/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /studio/ldap/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /studio/ldap/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /studio/ldap/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /studio/ldap/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | ldap 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | ldap 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-security 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 40 | 41 | org.springframework.security 42 | spring-security-ldap 43 | 44 | 45 | org.springframework.ldap 46 | spring-ldap-core 47 | 48 | 49 | com.unboundid 50 | unboundid-ldapsdk 51 | 52 | 53 | org.projectlombok 54 | lombok 55 | true 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-starter-test 60 | test 61 | 62 | 63 | org.springframework.security 64 | spring-security-test 65 | test 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.springframework.boot 73 | spring-boot-maven-plugin 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /studio/ldap/src/main/java/com/example/ldap/LdapApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.ldap; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 8 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 10 | import org.springframework.security.crypto.password.LdapShaPasswordEncoder; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.security.Principal; 15 | 16 | @SpringBootApplication 17 | public class LdapApplication { 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(LdapApplication.class, args); 21 | } 22 | } 23 | 24 | @RestController 25 | class GreetingsRestController { 26 | 27 | @GetMapping("/greeting") 28 | String greet(Principal p) { 29 | return "hello " + p.getName() + "!"; 30 | } 31 | } 32 | 33 | @Configuration 34 | @EnableWebSecurity 35 | class LdapSecurityConfiguration extends WebSecurityConfigurerAdapter { 36 | 37 | @Override 38 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 39 | //@formatter:off 40 | auth 41 | .ldapAuthentication() 42 | .userDnPatterns("uid={0},ou=people") 43 | .groupSearchBase("ou=groups") 44 | .contextSource() 45 | .url("ldap://127.0.0.1:8389/dc=springframework,dc=org") 46 | .and() 47 | .passwordCompare() 48 | .passwordAttribute("userPassword") 49 | .passwordEncoder(new LdapShaPasswordEncoder()); 50 | //@formatter:on 51 | } 52 | 53 | @Override 54 | protected void configure(HttpSecurity http) throws Exception { 55 | 56 | http.httpBasic(); 57 | 58 | http.authorizeRequests().anyRequest().authenticated(); 59 | } 60 | } -------------------------------------------------------------------------------- /studio/ldap/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.ldap.embedded.port=8389 2 | spring.ldap.embedded.ldif=classpath:test-server.ldif 3 | spring.ldap.embedded.base-dn=dc=springframework,dc=org -------------------------------------------------------------------------------- /studio/ldap/src/main/resources/test-server.ldif: -------------------------------------------------------------------------------- 1 | dn: dc=springframework,dc=org 2 | objectclass: top 3 | objectclass: domain 4 | objectclass: extensibleObject 5 | dc: springframework 6 | 7 | dn: ou=groups,dc=springframework,dc=org 8 | objectclass: top 9 | objectclass: organizationalUnit 10 | ou: groups 11 | 12 | dn: ou=subgroups,ou=groups,dc=springframework,dc=org 13 | objectclass: top 14 | objectclass: organizationalUnit 15 | ou: subgroups 16 | 17 | dn: ou=people,dc=springframework,dc=org 18 | objectclass: top 19 | objectclass: organizationalUnit 20 | ou: people 21 | 22 | dn: ou=space cadets,dc=springframework,dc=org 23 | objectclass: top 24 | objectclass: organizationalUnit 25 | ou: space cadets 26 | 27 | dn: ou=\"quoted people\",dc=springframework,dc=org 28 | objectclass: top 29 | objectclass: organizationalUnit 30 | ou: "quoted people" 31 | 32 | dn: ou=otherpeople,dc=springframework,dc=org 33 | objectclass: top 34 | objectclass: organizationalUnit 35 | ou: otherpeople 36 | 37 | dn: uid=ben,ou=people,dc=springframework,dc=org 38 | objectclass: top 39 | objectclass: person 40 | objectclass: organizationalPerson 41 | objectclass: inetOrgPerson 42 | cn: Ben Alex 43 | sn: Alex 44 | uid: ben 45 | userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ= 46 | 47 | dn: uid=bob,ou=people,dc=springframework,dc=org 48 | objectclass: top 49 | objectclass: person 50 | objectclass: organizationalPerson 51 | objectclass: inetOrgPerson 52 | cn: Bob Hamilton 53 | sn: Hamilton 54 | uid: bob 55 | userPassword: bobspassword 56 | 57 | dn: uid=joe,ou=otherpeople,dc=springframework,dc=org 58 | objectclass: top 59 | objectclass: person 60 | objectclass: organizationalPerson 61 | objectclass: inetOrgPerson 62 | cn: Joe Smeth 63 | sn: Smeth 64 | uid: joe 65 | userPassword: joespassword 66 | 67 | dn: cn=mouse\, jerry,ou=people,dc=springframework,dc=org 68 | objectclass: top 69 | objectclass: person 70 | objectclass: organizationalPerson 71 | objectclass: inetOrgPerson 72 | cn: Mouse, Jerry 73 | sn: Mouse 74 | uid: jerry 75 | userPassword: jerryspassword 76 | 77 | dn: cn=slash/guy,ou=people,dc=springframework,dc=org 78 | objectclass: top 79 | objectclass: person 80 | objectclass: organizationalPerson 81 | objectclass: inetOrgPerson 82 | cn: slash/guy 83 | sn: Slash 84 | uid: slashguy 85 | userPassword: slashguyspassword 86 | 87 | dn: cn=quote\"guy,ou=\"quoted people\",dc=springframework,dc=org 88 | objectclass: top 89 | objectclass: person 90 | objectclass: organizationalPerson 91 | objectclass: inetOrgPerson 92 | cn: quote\"guy 93 | sn: Quote 94 | uid: quoteguy 95 | userPassword: quoteguyspassword 96 | 97 | dn: uid=space cadet,ou=space cadets,dc=springframework,dc=org 98 | objectclass: top 99 | objectclass: person 100 | objectclass: organizationalPerson 101 | objectclass: inetOrgPerson 102 | cn: Space Cadet 103 | sn: Cadet 104 | uid: space cadet 105 | userPassword: spacecadetspassword 106 | 107 | 108 | 109 | dn: cn=developers,ou=groups,dc=springframework,dc=org 110 | objectclass: top 111 | objectclass: groupOfUniqueNames 112 | cn: developers 113 | ou: developer 114 | uniqueMember: uid=ben,ou=people,dc=springframework,dc=org 115 | uniqueMember: uid=bob,ou=people,dc=springframework,dc=org 116 | 117 | dn: cn=managers,ou=groups,dc=springframework,dc=org 118 | objectclass: top 119 | objectclass: groupOfUniqueNames 120 | cn: managers 121 | ou: manager 122 | uniqueMember: uid=ben,ou=people,dc=springframework,dc=org 123 | uniqueMember: cn=mouse\, jerry,ou=people,dc=springframework,dc=org 124 | 125 | dn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=org 126 | objectclass: top 127 | objectclass: groupOfUniqueNames 128 | cn: submanagers 129 | ou: submanager 130 | uniqueMember: uid=ben,ou=people,dc=springframework,dc=org -------------------------------------------------------------------------------- /studio/ldap/src/test/java/com/example/ldap/LdapApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.ldap; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class LdapApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /studio/login/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /studio/login/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/studio/login/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /studio/login/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /studio/login/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /studio/login/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | login 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | login 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.1.0.BUILD-SNAPSHOT 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-actuator 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-security 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-thymeleaf 39 | 40 | 41 | nz.net.ultraq.thymeleaf 42 | thymeleaf-layout-dialect 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-web 47 | 48 | 49 | org.projectlombok 50 | lombok 51 | true 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-starter-test 56 | test 57 | 58 | 59 | org.springframework.security 60 | spring-security-test 61 | test 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-maven-plugin 70 | 71 | 72 | 73 | 74 | 75 | 76 | spring-snapshots 77 | Spring Snapshots 78 | https://repo.spring.io/snapshot 79 | 80 | true 81 | 82 | 83 | 84 | spring-milestones 85 | Spring Milestones 86 | https://repo.spring.io/milestone 87 | 88 | false 89 | 90 | 91 | 92 | 93 | 94 | 95 | spring-snapshots 96 | Spring Snapshots 97 | https://repo.spring.io/snapshot 98 | 99 | true 100 | 101 | 102 | 103 | spring-milestones 104 | Spring Milestones 105 | https://repo.spring.io/milestone 106 | 107 | false 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /studio/login/src/main/java/com/example/login/LoginApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.login; 2 | 3 | import org.springframework.beans.factory.InitializingBean; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 11 | import org.springframework.security.core.userdetails.User; 12 | import org.springframework.security.core.userdetails.UserDetails; 13 | import org.springframework.security.provisioning.InMemoryUserDetailsManager; 14 | import org.springframework.security.provisioning.UserDetailsManager; 15 | import org.springframework.stereotype.Controller; 16 | import org.springframework.ui.Model; 17 | import org.springframework.web.bind.annotation.ControllerAdvice; 18 | import org.springframework.web.bind.annotation.GetMapping; 19 | import org.springframework.web.bind.annotation.ModelAttribute; 20 | 21 | import java.security.Principal; 22 | 23 | @SpringBootApplication 24 | public class LoginApplication { 25 | 26 | public static void main(String[] args) { 27 | SpringApplication.run(LoginApplication.class, args); 28 | } 29 | 30 | @Bean 31 | UserDetailsManager memory() { 32 | return new InMemoryUserDetailsManager(); 33 | } 34 | 35 | @Bean 36 | InitializingBean initializer(UserDetailsManager manager) { 37 | return () -> { 38 | 39 | UserDetails josh = User.withDefaultPasswordEncoder().username("jlong").password("password").roles("USER").build(); 40 | manager.createUser(josh); 41 | 42 | UserDetails rob = User.withUserDetails(josh).username("rwinch").build(); 43 | manager.createUser(rob); 44 | }; 45 | } 46 | } 47 | 48 | @ControllerAdvice 49 | class PrincipalControllerAdvice { 50 | 51 | @ModelAttribute("currentUser") 52 | Principal principal(Principal p) { 53 | return p; 54 | } 55 | } 56 | 57 | @Controller 58 | class LoginController { 59 | 60 | @GetMapping("/") 61 | String index(Model model) { 62 | return "hidden"; 63 | } 64 | 65 | @GetMapping("/login") 66 | String login() { 67 | return "login"; 68 | } 69 | 70 | @GetMapping("/logout-success") 71 | String logout() { 72 | return "logout"; 73 | } 74 | 75 | } 76 | 77 | @Configuration 78 | @EnableWebSecurity 79 | class SecurityConfiguration extends WebSecurityConfigurerAdapter { 80 | 81 | @Override 82 | protected void configure(HttpSecurity http) throws Exception { 83 | 84 | http 85 | .authorizeRequests().anyRequest().authenticated(); 86 | 87 | http 88 | .formLogin().loginPage("/login").permitAll(); 89 | 90 | http 91 | .logout().logoutUrl("/logout").logoutSuccessUrl("/logout-success").permitAll(); 92 | } 93 | } -------------------------------------------------------------------------------- /studio/login/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/studio/login/src/main/resources/application.properties -------------------------------------------------------------------------------- /studio/login/src/main/resources/templates/hidden.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Yahaha! You Found Me! 4 | 5 |
6 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /studio/login/src/main/resources/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Spring Security Livelessons 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 |
15 |
16 | 17 |
18 |
19 | 20 | -------------------------------------------------------------------------------- /studio/login/src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Please Log In 7 | 8 | 9 |
10 | 11 |

Please Log In

12 | 13 |
14 |
Invalid username and password.
15 |
You have been logged out.
16 |

17 | 18 | 19 |

20 |

21 | 22 | 23 |

24 | 25 |
26 |
27 | 28 | -------------------------------------------------------------------------------- /studio/login/src/main/resources/templates/logout.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Goodbye! 7 | 8 | 9 |
10 |

..Don't Forget to Write! 11 |

12 |
13 | 14 | -------------------------------------------------------------------------------- /studio/login/src/test/java/com/example/login/LoginApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.login; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class LoginApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /studio/password-encoding-and-migration/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /studio/password-encoding-and-migration/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/studio/password-encoding-and-migration/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /studio/password-encoding-and-migration/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /studio/password-encoding-and-migration/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /studio/password-encoding-and-migration/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | custom-authentication 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | custom-authentication 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.1.0.BUILD-SNAPSHOT 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-actuator 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-security 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 40 | 41 | 42 | org.projectlombok 43 | lombok 44 | true 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | org.springframework.security 53 | spring-security-test 54 | test 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-maven-plugin 63 | 64 | 65 | 66 | 67 | 68 | 69 | spring-snapshots 70 | Spring Snapshots 71 | https://repo.spring.io/snapshot 72 | 73 | true 74 | 75 | 76 | 77 | spring-milestones 78 | Spring Milestones 79 | https://repo.spring.io/milestone 80 | 81 | false 82 | 83 | 84 | 85 | 86 | 87 | 88 | spring-snapshots 89 | Spring Snapshots 90 | https://repo.spring.io/snapshot 91 | 92 | true 93 | 94 | 95 | 96 | spring-milestones 97 | Spring Milestones 98 | https://repo.spring.io/milestone 99 | 100 | false 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /studio/password-encoding-and-migration/src/main/java/com/example/customauthentication/CustomAuthenticationApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.customauthentication; 2 | 3 | import lombok.extern.log4j.Log4j2; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 11 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 12 | import org.springframework.security.core.GrantedAuthority; 13 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 14 | import org.springframework.security.core.userdetails.UserDetails; 15 | import org.springframework.security.core.userdetails.UserDetailsPasswordService; 16 | import org.springframework.security.core.userdetails.UserDetailsService; 17 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 18 | import org.springframework.security.crypto.factory.PasswordEncoderFactories; 19 | import org.springframework.security.crypto.password.DelegatingPasswordEncoder; 20 | import org.springframework.security.crypto.password.MessageDigestPasswordEncoder; 21 | import org.springframework.security.crypto.password.PasswordEncoder; 22 | import org.springframework.web.bind.annotation.GetMapping; 23 | import org.springframework.web.bind.annotation.RestController; 24 | 25 | import java.security.Principal; 26 | import java.util.*; 27 | import java.util.concurrent.ConcurrentHashMap; 28 | import java.util.stream.Collectors; 29 | import java.util.stream.Stream; 30 | 31 | @SpringBootApplication 32 | public class CustomAuthenticationApplication { 33 | 34 | // @Bean 35 | PasswordEncoder oldPasswordEncoder() { 36 | String md5 = "MD5"; 37 | return new DelegatingPasswordEncoder(md5, 38 | Collections.singletonMap(md5, new MessageDigestPasswordEncoder(md5))); 39 | } 40 | 41 | @Bean 42 | PasswordEncoder passwordEncoder() { 43 | return PasswordEncoderFactories.createDelegatingPasswordEncoder(); 44 | } 45 | 46 | @Bean 47 | CustomUserDetailsService customUserDetailsService() { 48 | Collection users = Arrays.asList( 49 | new CustomUserDetails("jlong", oldPasswordEncoder().encode("password"), true, "USER"), 50 | new CustomUserDetails("rwinch", oldPasswordEncoder().encode("password"), true, "USER", "ADMIN") 51 | ); 52 | return new CustomUserDetailsService(users); 53 | } 54 | 55 | public static void main(String[] args) { 56 | SpringApplication.run(CustomAuthenticationApplication.class, args); 57 | } 58 | } 59 | 60 | @RestController 61 | class GreetingRestController { 62 | 63 | @GetMapping("/greeting") 64 | String greet(Principal p) { 65 | return "greetings, " + p.getName() + "!"; 66 | } 67 | } 68 | 69 | @Configuration 70 | @EnableWebSecurity 71 | class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter { 72 | 73 | @Override 74 | protected void configure(HttpSecurity http) throws Exception { 75 | http.httpBasic(); 76 | http.authorizeRequests().anyRequest().authenticated(); 77 | } 78 | } 79 | 80 | @Log4j2 81 | class CustomUserDetailsService implements UserDetailsService, 82 | UserDetailsPasswordService { 83 | 84 | private final Map users = new ConcurrentHashMap<>(); 85 | 86 | public CustomUserDetailsService(Collection seedUsers) { 87 | seedUsers.forEach(user -> this.users.put(user.getUsername(), user)); 88 | this.users.forEach((k, v) -> log.info(k + "=" + v.getPassword())); 89 | } 90 | 91 | @Override 92 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 93 | if (this.users.containsKey(username)) { 94 | return this.users.get(username); 95 | } 96 | throw new UsernameNotFoundException(String.format("couldn't find %s!", username)); 97 | } 98 | 99 | @Override 100 | public UserDetails updatePassword(UserDetails user, String newPassword) { 101 | log.info("prompted to updated password for user " + user.getUsername() + " to " + newPassword); 102 | 103 | this.users.put(user.getUsername(), new CustomUserDetails( 104 | user.getUsername(), 105 | newPassword, 106 | user.isEnabled(), 107 | user.getAuthorities().stream().map(GrantedAuthority::getAuthority).toArray(String[]::new) 108 | )); 109 | 110 | return this.loadUserByUsername(user.getUsername()); 111 | } 112 | } 113 | 114 | 115 | class CustomUserDetails implements UserDetails { 116 | 117 | private final Set authorities; 118 | private final String username, password; 119 | private final boolean active; 120 | 121 | public CustomUserDetails(String username, String password, boolean active, String... authorities) { 122 | this.username = username; 123 | this.password = password; 124 | this.active = active; 125 | this.authorities = Stream 126 | .of(authorities) 127 | .map(SimpleGrantedAuthority::new) 128 | .collect(Collectors.toSet()); 129 | } 130 | 131 | @Override 132 | public Collection getAuthorities() { 133 | return this.authorities; 134 | } 135 | 136 | @Override 137 | public String getPassword() { 138 | return this.password; 139 | } 140 | 141 | @Override 142 | public String getUsername() { 143 | return this.username; 144 | } 145 | 146 | @Override 147 | public boolean isAccountNonExpired() { 148 | return this.active; 149 | } 150 | 151 | @Override 152 | public boolean isAccountNonLocked() { 153 | return this.active; 154 | } 155 | 156 | @Override 157 | public boolean isCredentialsNonExpired() { 158 | return this.active; 159 | } 160 | 161 | @Override 162 | public boolean isEnabled() { 163 | return this.active; 164 | } 165 | } -------------------------------------------------------------------------------- /studio/password-encoding-and-migration/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | management.endpoints.web.exposure.include=* 2 | -------------------------------------------------------------------------------- /studio/password-encoding-and-migration/src/test/java/com/example/customauthentication/CustomAuthenticationApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.customauthentication; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CustomAuthenticationApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /user-details/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | user-details 7 | 8 | livelessons 9 | authentication 10 | 0.0.1-SNAPSHOT 11 | .. 12 | 13 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-security 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | com.h2database 27 | h2 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-jdbc 33 | 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-test 39 | test 40 | 41 | 42 | org.springframework.security 43 | spring-security-test 44 | test 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-maven-plugin 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /user-details/src/main/java/livelessons/AuthenticationApplication.java: -------------------------------------------------------------------------------- 1 | package livelessons; 2 | 3 | import org.apache.commons.logging.Log; 4 | import org.apache.commons.logging.LogFactory; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.context.annotation.Profile; 10 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 11 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 12 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 13 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 14 | import org.springframework.security.crypto.factory.PasswordEncoderFactories; 15 | import org.springframework.security.crypto.password.LdapShaPasswordEncoder; 16 | import org.springframework.security.crypto.password.PasswordEncoder; 17 | import org.springframework.security.provisioning.InMemoryUserDetailsManager; 18 | import org.springframework.security.provisioning.JdbcUserDetailsManager; 19 | import org.springframework.security.provisioning.UserDetailsManager; 20 | import org.springframework.web.bind.annotation.GetMapping; 21 | import org.springframework.web.bind.annotation.RestController; 22 | 23 | import javax.sql.DataSource; 24 | import java.security.Principal; 25 | 26 | @SpringBootApplication 27 | public class AuthenticationApplication { 28 | 29 | private Log log = LogFactory.getLog(getClass()); 30 | 31 | public static void main(String args[]) { 32 | SpringApplication.run(AuthenticationApplication.class, args); 33 | } 34 | 35 | @Bean 36 | PasswordEncoder passwordEncoder() { 37 | return PasswordEncoderFactories.createDelegatingPasswordEncoder(); 38 | } 39 | 40 | @Bean 41 | @Profile("memory") 42 | UserDetailsManager memory() { 43 | log.info("starting the memory " + InMemoryUserDetailsManager.class.getName()); 44 | return new InMemoryUserDetailsManager(); 45 | } 46 | 47 | @Bean 48 | @Profile("jdbc") 49 | UserDetailsManager jdbc(DataSource ds) { 50 | log.info("starting the JDBC " + JdbcUserDetailsManager.class.getName()); 51 | JdbcUserDetailsManager jdbc = new JdbcUserDetailsManager(); 52 | jdbc.setDataSource(ds); 53 | return jdbc; 54 | } 55 | 56 | @Configuration 57 | @EnableWebSecurity 58 | public static class BasicAuthorizationConfig extends WebSecurityConfigurerAdapter { 59 | 60 | @Override 61 | protected void configure(HttpSecurity http) throws Exception { 62 | http.csrf().and().httpBasic().and().authorizeRequests().anyRequest() 63 | .authenticated(); 64 | } 65 | 66 | } 67 | 68 | } 69 | 70 | @RestController 71 | class GreetingsRestController { 72 | 73 | @GetMapping("/greet") 74 | String greet(Principal p) { 75 | return "hello, " + p.getName() + "!"; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /user-details/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/user-details/src/main/resources/application.properties -------------------------------------------------------------------------------- /user-details/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | drop table if exists users; 2 | 3 | create table users ( 4 | username varchar_ignorecase(50) not null primary key, 5 | password varchar_ignorecase(500) not null, 6 | enabled boolean not null 7 | ); 8 | 9 | 10 | drop table if exists authorities; 11 | create table authorities ( 12 | username varchar_ignorecase(50) not null, 13 | authority varchar_ignorecase(50) not null, 14 | constraint fk_authorities_USERS foreign key (username) references users (username) 15 | ); 16 | create unique index ix_auth_username 17 | on authorities (username, authority); -------------------------------------------------------------------------------- /user-details/src/test/java/livelessons/JdbcUserDetailsServiceTest.java: -------------------------------------------------------------------------------- 1 | package livelessons; 2 | 3 | import org.springframework.test.context.ActiveProfiles; 4 | 5 | @ActiveProfiles("jdbc") 6 | public class JdbcUserDetailsServiceTest extends UserDetailsServiceTestBaseClass { 7 | 8 | } -------------------------------------------------------------------------------- /user-details/src/test/java/livelessons/MemoryUserDetailsServiceTest.java: -------------------------------------------------------------------------------- 1 | package livelessons; 2 | 3 | import org.springframework.test.context.ActiveProfiles; 4 | 5 | /** 6 | * @author Josh Long 7 | */ 8 | @ActiveProfiles("memory") 9 | public class MemoryUserDetailsServiceTest extends UserDetailsServiceTestBaseClass { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /user-details/src/test/java/livelessons/SimpleUserDetailsServiceTest.java: -------------------------------------------------------------------------------- 1 | package livelessons; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 6 | import org.springframework.security.authentication.dao.DaoAuthenticationProvider; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.core.authority.AuthorityUtils; 9 | import org.springframework.security.core.userdetails.User; 10 | import org.springframework.security.core.userdetails.UserDetails; 11 | import org.springframework.security.core.userdetails.UserDetailsService; 12 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 13 | import org.springframework.security.crypto.factory.PasswordEncoderFactories; 14 | import org.springframework.security.crypto.password.DelegatingPasswordEncoder; 15 | import org.springframework.security.crypto.password.PasswordEncoder; 16 | import org.springframework.security.provisioning.InMemoryUserDetailsManager; 17 | import org.springframework.security.util.FieldUtils; 18 | 19 | import java.lang.reflect.Field; 20 | import java.util.Collection; 21 | import java.util.Map; 22 | import java.util.stream.Collectors; 23 | import java.util.stream.IntStream; 24 | 25 | public class SimpleUserDetailsServiceTest { 26 | 27 | private final PasswordEncoder passwordEncoder = PasswordEncoderFactories 28 | .createDelegatingPasswordEncoder(); 29 | 30 | private final UserDetailsService userDetailsService = new InMemoryUserDetailsManager( 31 | this.contributeUsers()); 32 | 33 | private final DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider() { 34 | { 35 | setPasswordEncoder(passwordEncoder); 36 | setUserDetailsService(userDetailsService); 37 | } 38 | }; 39 | 40 | @Test 41 | @SuppressWarnings("unchecked") 42 | public void encode() throws Exception { 43 | String encodedPassword = this.passwordEncoder.encode("password"); 44 | Assert.assertTrue(this.passwordEncoder.matches("password", encodedPassword)); 45 | 46 | // is the ID in the encoded PW? 47 | Field idForEncode = fieldFor(DelegatingPasswordEncoder.class, "idForEncode"); 48 | String id = String.class.cast(idForEncode.get(this.passwordEncoder)); 49 | Assert.assertTrue(encodedPassword.contains(id)); 50 | 51 | // is the default PasswordEncoder BCrypt? 52 | Field pwEncoderMapField = fieldFor(DelegatingPasswordEncoder.class, 53 | "idToPasswordEncoder"); 54 | Map pwEncoderMap = (Map) pwEncoderMapField 55 | .get(this.passwordEncoder); 56 | Assert.assertTrue(pwEncoderMap.get(id) instanceof BCryptPasswordEncoder); 57 | } 58 | 59 | @Test 60 | public void loadUserByUsername() { 61 | UserDetails userDetails = this.userDetailsService.loadUserByUsername("user1"); 62 | Assert.assertNotNull(userDetails); 63 | } 64 | 65 | @Test 66 | public void authenticate() { 67 | Authentication authentication = new UsernamePasswordAuthenticationToken("user1", 68 | "password1"); 69 | Authentication result = this.daoAuthenticationProvider 70 | .authenticate(authentication); 71 | Assert.assertTrue(result.isAuthenticated()); 72 | } 73 | 74 | private Collection contributeUsers() { 75 | return IntStream.range(0, 5) 76 | .mapToObj(i -> new User("user" + i, 77 | this.passwordEncoder.encode("password" + i), true, true, true, 78 | true, AuthorityUtils.createAuthorityList("USER"))) 79 | .collect(Collectors.toList()); 80 | } 81 | 82 | private Field fieldFor(Class aClass, String fieldName) { 83 | Field idForEncode = FieldUtils.getField(aClass, fieldName); 84 | idForEncode.setAccessible(true); 85 | return idForEncode; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /user-details/src/test/java/livelessons/UserDetailsServiceTestBaseClass.java: -------------------------------------------------------------------------------- 1 | package livelessons; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.context.event.ApplicationReadyEvent; 8 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.context.ApplicationListener; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.context.annotation.Profile; 13 | import org.springframework.security.core.authority.AuthorityUtils; 14 | import org.springframework.security.core.userdetails.User; 15 | import org.springframework.security.core.userdetails.UserDetails; 16 | import org.springframework.security.crypto.password.PasswordEncoder; 17 | import org.springframework.security.provisioning.UserDetailsManager; 18 | import org.springframework.security.test.context.support.WithMockUser; 19 | import org.springframework.test.context.junit4.SpringRunner; 20 | import org.springframework.test.web.servlet.MockMvc; 21 | 22 | import java.util.Collection; 23 | import java.util.function.Consumer; 24 | import java.util.stream.Collectors; 25 | import java.util.stream.IntStream; 26 | 27 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 28 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; 29 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 30 | 31 | @SpringBootTest 32 | @AutoConfigureMockMvc 33 | @RunWith(SpringRunner.class) 34 | public class UserDetailsServiceTestBaseClass { 35 | 36 | private final static String USERNAME = "user1"; 37 | 38 | @Autowired 39 | private UserDetailsManager userDetailsManager; 40 | 41 | @Autowired 42 | private MockMvc mvc; 43 | 44 | @Test 45 | @WithMockUser(USERNAME) 46 | public void authenticate() throws Exception { 47 | 48 | String expectedString = String.format("hello, %s!", USERNAME); 49 | 50 | this.mvc.perform(get("/greet")).andExpect(status().isOk()) 51 | .andExpect(content().string(expectedString)); 52 | } 53 | 54 | @Test 55 | public void loadUserByUsername() { 56 | UserDetails user = this.userDetailsManager.loadUserByUsername("user1"); 57 | Assert.assertNotNull(user); 58 | } 59 | 60 | @Test 61 | public void createUser() { 62 | String user = "user"; 63 | 64 | this.userDetailsManager.deleteUser(user); 65 | 66 | UserDetails jane = User.withDefaultPasswordEncoder().username(user).password("pw") 67 | .roles("USER").build(); 68 | this.userDetailsManager.createUser(jane); 69 | Assert.assertTrue(this.userDetailsManager.userExists(jane.getUsername())); 70 | } 71 | 72 | } 73 | 74 | @Configuration 75 | @Profile("!ldap") 76 | class Initializer implements ApplicationListener { 77 | 78 | private final PasswordEncoder passwordEncoder; 79 | 80 | private final UserDetailsManager userDetailsManager; 81 | 82 | Initializer(PasswordEncoder passwordEncoder, UserDetailsManager userDetailsManager) { 83 | this.passwordEncoder = passwordEncoder; 84 | this.userDetailsManager = userDetailsManager; 85 | } 86 | 87 | @Override 88 | public void onApplicationEvent(ApplicationReadyEvent evt) { 89 | Consumer process = user -> { 90 | this.userDetailsManager.deleteUser(user.getUsername()); 91 | this.userDetailsManager.createUser(user); 92 | }; 93 | 94 | Collection userDetails = IntStream.range(0, 5) 95 | .mapToObj(i -> new User("user" + i, 96 | this.passwordEncoder.encode("password" + i), true, true, true, 97 | true, AuthorityUtils.createAuthorityList("USER"))) 98 | .collect(Collectors.toList()); 99 | 100 | userDetails.forEach(process); 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /xauth-app/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | livelessons 7 | authentication 8 | 0.0.1-SNAPSHOT 9 | .. 10 | 11 | xauth-app 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-security 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-web 20 | 21 | 22 | livelessons 23 | xauth 24 | 0.0.1-SNAPSHOT 25 | 26 | 27 | org.projectlombok 28 | lombok 29 | true 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | org.springframework.security 38 | spring-security-test 39 | test 40 | 41 | 42 | 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-maven-plugin 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /xauth-app/src/main/java/livelessons/custom/CustomApplication.java: -------------------------------------------------------------------------------- 1 | package livelessons.custom; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.core.Ordered; 8 | import org.springframework.core.annotation.Order; 9 | import org.springframework.security.authentication.AuthenticationManager; 10 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 11 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 12 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 13 | import org.springframework.security.core.userdetails.User; 14 | import org.springframework.security.core.userdetails.UserDetails; 15 | import org.springframework.security.provisioning.InMemoryUserDetailsManager; 16 | import org.springframework.web.bind.annotation.GetMapping; 17 | import org.springframework.web.bind.annotation.RestController; 18 | 19 | import java.security.Principal; 20 | 21 | /** 22 | * curl -v -X POST -F "username=rob" -F"password=pw" http://localhost:8080/authenticate 23 | * curl -v -H"x-auth-token: rob:1532068547605:c704d3c1c78a17922070a8e7b7e02144" 24 | * http://localhost:8080/greet 25 | */ 26 | @SpringBootApplication 27 | public class CustomApplication { 28 | 29 | public static void main(String[] args) { 30 | SpringApplication.run(CustomApplication.class, args); 31 | } 32 | 33 | } 34 | 35 | @Configuration 36 | class UserConfiguration { 37 | 38 | @Bean 39 | InMemoryUserDetailsManager authentication() { 40 | return new InMemoryUserDetailsManager(user("rob"), user("josh")); 41 | } 42 | 43 | private static UserDetails user(String u) { 44 | return User.withDefaultPasswordEncoder().roles("USER").username(u).password("pw") 45 | .build(); 46 | } 47 | 48 | } 49 | 50 | @Configuration 51 | @EnableWebSecurity 52 | class CustomSecurity extends WebSecurityConfigurerAdapter { 53 | 54 | @Bean 55 | @Override 56 | public AuthenticationManager authenticationManagerBean() throws Exception { 57 | return super.authenticationManagerBean(); 58 | } 59 | 60 | @Override 61 | protected void configure(HttpSecurity http) throws Exception { 62 | 63 | http.authorizeRequests().mvcMatchers("/greet").authenticated().anyRequest() 64 | .permitAll().and().httpBasic().and().csrf().disable(); 65 | } 66 | 67 | } 68 | 69 | @RestController 70 | class GreetingsRestController { 71 | 72 | @GetMapping("/greet") 73 | String greet(Principal p) { 74 | return "hello, " + p.getName() + "!"; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /xauth-app/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/xauth-app/src/main/resources/application.properties -------------------------------------------------------------------------------- /xauth-app/src/test/java/livelessons/custom/GreetingsRestControllerTest.java: -------------------------------------------------------------------------------- 1 | package livelessons.custom; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.junit.Assert; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; 14 | import org.springframework.test.context.junit4.SpringRunner; 15 | import org.springframework.test.web.servlet.MockMvc; 16 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 17 | import org.springframework.web.context.WebApplicationContext; 18 | 19 | import java.util.Map; 20 | import java.util.concurrent.atomic.AtomicReference; 21 | 22 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.anonymous; 23 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 24 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 25 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; 26 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 27 | 28 | @Slf4j 29 | @RunWith(SpringRunner.class) 30 | @SpringBootTest 31 | @AutoConfigureMockMvc 32 | public class GreetingsRestControllerTest { 33 | 34 | @Autowired 35 | private ObjectMapper objectMapper; 36 | 37 | @Autowired 38 | private WebApplicationContext context; 39 | 40 | private MockMvc mvc; 41 | 42 | @Before 43 | public void setup() { 44 | this.mvc = MockMvcBuilders.webAppContextSetup(this.context) 45 | .apply(SecurityMockMvcConfigurers.springSecurity()).build(); 46 | } 47 | 48 | @Test 49 | public void greetFail() throws Exception { 50 | 51 | this.mvc.perform(get("/greet").with(anonymous())) 52 | .andExpect(status().is4xxClientError()); 53 | } 54 | 55 | @Test 56 | public void greetSuccess() throws Exception { 57 | 58 | TypeReference> typeReference = new TypeReference>() { 59 | }; 60 | 61 | AtomicReference tokenReference = new AtomicReference<>(); 62 | 63 | String rob = "rob"; 64 | this.mvc.perform( 65 | post("/authenticate").param("username", rob).param("password", "pw")) 66 | .andExpect(result -> { 67 | String response = result.getResponse().getContentAsString(); 68 | log.info("response: " + response); 69 | 70 | Map map = this.objectMapper.readValue(response, 71 | typeReference); 72 | String token = map.get("token"); 73 | Assert.assertTrue(token.contains(rob)); 74 | tokenReference.set(token); 75 | }); 76 | 77 | this.mvc.perform(get("/greet").header("x-auth-token", tokenReference.get())) 78 | .andExpect(content().string("hello, " + rob + "!")); 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /xauth/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | livelessons 7 | authentication 8 | 0.0.1-SNAPSHOT 9 | .. 10 | 11 | xauth 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-security 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-web 20 | 21 | 22 | org.projectlombok 23 | lombok 24 | true 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-test 29 | test 30 | 31 | 32 | org.springframework.security 33 | spring-security-test 34 | test 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /xauth/src/main/java/livelessons/xauth/TokenUtils.java: -------------------------------------------------------------------------------- 1 | package livelessons.xauth; 2 | 3 | import org.springframework.security.core.userdetails.UserDetails; 4 | import org.springframework.security.crypto.codec.Hex; 5 | import org.springframework.util.ReflectionUtils; 6 | 7 | import java.security.MessageDigest; 8 | import java.security.NoSuchAlgorithmException; 9 | import java.util.Optional; 10 | 11 | abstract class TokenUtils { 12 | 13 | private static final String MAGIC_KEY = "obfuscate"; 14 | 15 | private static final MessageDigest MESSAGE_DIGEST = buildDigest(); 16 | 17 | private static MessageDigest buildDigest() { 18 | try { 19 | return MessageDigest.getInstance("MD5"); 20 | } 21 | catch (NoSuchAlgorithmException e) { 22 | ReflectionUtils.rethrowRuntimeException(e); 23 | } 24 | return null; 25 | } 26 | 27 | static String createToken(UserDetails userDetails) { 28 | long expires = System.currentTimeMillis() + 1000L * 60 * 60; 29 | return userDetails.getUsername() + ":" + expires + ":" 30 | + computeSignature(userDetails, expires); 31 | } 32 | 33 | private static String computeSignature(UserDetails userDetails, long expires) { 34 | String signature = ""; 35 | signature += (userDetails.getUsername()) + (":"); 36 | signature += (expires) + (":"); 37 | signature += (userDetails.getPassword()) + (":"); 38 | signature += (TokenUtils.MAGIC_KEY); 39 | return new String(Hex.encode(MESSAGE_DIGEST.digest(signature.getBytes()))); 40 | } 41 | 42 | static String getUserNameFromToken(String authToken) { 43 | return Optional.ofNullable(authToken).map(at -> at.split(":")[0]).orElse(null); 44 | } 45 | 46 | static boolean validateToken(String authToken, UserDetails userDetails) { 47 | String[] parts = authToken.split(":"); 48 | long expires = Long.parseLong(parts[1]); 49 | String signature = parts[2]; 50 | String signatureToMatch = computeSignature(userDetails, expires); 51 | return expires >= System.currentTimeMillis() 52 | && signature.equals(signatureToMatch); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /xauth/src/main/java/livelessons/xauth/XAuthAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package livelessons.xauth; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.context.annotation.Import; 5 | 6 | @Configuration 7 | @Import(XAuthConfiguration.class) 8 | public class XAuthAutoConfiguration { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /xauth/src/main/java/livelessons/xauth/XAuthConfiguration.java: -------------------------------------------------------------------------------- 1 | package livelessons.xauth; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.authentication.AuthenticationManager; 6 | import org.springframework.security.core.userdetails.UserDetailsService; 7 | 8 | @Configuration 9 | class XAuthConfiguration { 10 | 11 | @Bean 12 | XAuthTokenRestController xAuthTokenRestController(AuthenticationManager am, 13 | UserDetailsService uds) { 14 | return new XAuthTokenRestController(am, uds); 15 | } 16 | 17 | @Bean 18 | XAuthTokenFilter tokenFilter(UserDetailsService uds) { 19 | return new XAuthTokenFilter(uds); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /xauth/src/main/java/livelessons/xauth/XAuthDslConfigurer.java: -------------------------------------------------------------------------------- 1 | package livelessons.xauth; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; 7 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 8 | 9 | @Slf4j 10 | public class XAuthDslConfigurer 11 | extends AbstractHttpConfigurer { 12 | 13 | @Override 14 | public void init(HttpSecurity builder) throws Exception { 15 | builder.httpBasic().and().csrf().disable(); 16 | } 17 | 18 | @Override 19 | public void configure(HttpSecurity builder) throws Exception { 20 | ApplicationContext context = builder.getSharedObject(ApplicationContext.class); 21 | XAuthTokenFilter xAuthTokenFilter = context.getBean(XAuthTokenFilter.class); 22 | builder.addFilterBefore(xAuthTokenFilter, 23 | UsernamePasswordAuthenticationFilter.class); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /xauth/src/main/java/livelessons/xauth/XAuthTokenFilter.java: -------------------------------------------------------------------------------- 1 | package livelessons.xauth; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 5 | import org.springframework.security.core.context.SecurityContextHolder; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | import org.springframework.security.core.userdetails.UserDetailsService; 8 | import org.springframework.web.filter.GenericFilterBean; 9 | 10 | import javax.servlet.FilterChain; 11 | import javax.servlet.ServletException; 12 | import javax.servlet.ServletRequest; 13 | import javax.servlet.ServletResponse; 14 | import javax.servlet.http.HttpServletRequest; 15 | import java.io.IOException; 16 | import java.util.Optional; 17 | 18 | @Slf4j 19 | class XAuthTokenFilter extends GenericFilterBean { 20 | 21 | private final UserDetailsService detailsService; 22 | 23 | private String xAuthTokenHeaderName; 24 | 25 | XAuthTokenFilter(UserDetailsService userDetailsService) { 26 | this(userDetailsService, "x-auth-token"); 27 | } 28 | 29 | XAuthTokenFilter(UserDetailsService userDetailsService, String xAuthTokenHeaderName) { 30 | this.detailsService = userDetailsService; 31 | this.xAuthTokenHeaderName = xAuthTokenHeaderName; 32 | } 33 | 34 | @Override 35 | public void doFilter(ServletRequest arg0, ServletResponse arg1, 36 | FilterChain filterChain) throws IOException, ServletException { 37 | HttpServletRequest httpServletRequest = HttpServletRequest.class.cast(arg0); 38 | String at = httpServletRequest.getHeader(this.xAuthTokenHeaderName); 39 | Optional.ofNullable(at).ifPresent(authToken -> { 40 | UserDetails details = this.detailsService 41 | .loadUserByUsername(TokenUtils.getUserNameFromToken(authToken)); 42 | if (TokenUtils.validateToken(authToken, details)) { 43 | UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( 44 | details, details.getPassword(), details.getAuthorities()); 45 | SecurityContextHolder.getContext().setAuthentication(token); 46 | } 47 | }); 48 | filterChain.doFilter(arg0, arg1); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /xauth/src/main/java/livelessons/xauth/XAuthTokenRestController.java: -------------------------------------------------------------------------------- 1 | package livelessons.xauth; 2 | 3 | import org.springframework.security.authentication.AuthenticationManager; 4 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 5 | import org.springframework.security.core.Authentication; 6 | import org.springframework.security.core.GrantedAuthority; 7 | import org.springframework.security.core.context.SecurityContextHolder; 8 | import org.springframework.security.core.userdetails.UserDetails; 9 | import org.springframework.security.core.userdetails.UserDetailsService; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestParam; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | import java.util.stream.Collectors; 17 | 18 | @RestController 19 | class XAuthTokenRestController { 20 | 21 | private final AuthenticationManager authenticationManager; 22 | 23 | private final UserDetailsService userDetailsService; 24 | 25 | XAuthTokenRestController(AuthenticationManager authenticationManager, 26 | UserDetailsService userDetailsService) { 27 | this.authenticationManager = authenticationManager; 28 | this.userDetailsService = userDetailsService; 29 | } 30 | 31 | @PostMapping(value = "/authenticate") 32 | Map authenticate(@RequestParam String username, 33 | @RequestParam String password) { 34 | 35 | UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( 36 | username, password); 37 | Authentication authentication = this.authenticationManager.authenticate(token); 38 | SecurityContextHolder.getContext().setAuthentication(authentication); 39 | 40 | UserDetails details = this.userDetailsService.loadUserByUsername(username); 41 | 42 | Map transfer = new HashMap<>(); 43 | transfer.put("token", TokenUtils.createToken(details)); 44 | transfer.put("username", details.getUsername()); 45 | transfer.put("roles", details.getAuthorities().stream() 46 | .map(GrantedAuthority::getAuthority).collect(Collectors.toList())); 47 | return transfer; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /xauth/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=livelessons.xauth.XAuthAutoConfiguration 2 | org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer=livelessons.xauth.XAuthDslConfigurer -------------------------------------------------------------------------------- /xauth/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-security-livelessons/authentication/238681ae99079652113fff69426783f7db864f03/xauth/src/main/resources/application.properties --------------------------------------------------------------------------------