├── .gitignore ├── SpringResourceServer ├── settings.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ ├── test │ │ └── java │ │ │ └── pk │ │ │ └── training │ │ │ └── basit │ │ │ └── SpringResourceServer │ │ │ └── SpringResourceServerApplicationTests.java │ └── main │ │ ├── java │ │ └── pk │ │ │ └── training │ │ │ └── basit │ │ │ ├── SpringResourceServerApplication.java │ │ │ ├── ServletInitializer.java │ │ │ ├── controller │ │ │ └── rest │ │ │ │ └── MessagesController.java │ │ │ ├── service │ │ │ └── JwtService.java │ │ │ ├── configuration │ │ │ └── ResourceServerConfiguration.java │ │ │ └── converter │ │ │ └── jwt │ │ │ └── CustomJwtGrantedAuthoritiesConverter.java │ │ └── resources │ │ └── application.properties ├── .gitignore ├── build.gradle ├── gradlew.bat └── gradlew ├── SpringAuthorizationServer ├── src │ ├── main │ │ ├── resources │ │ │ ├── i18n │ │ │ │ ├── validation_en_US.properties │ │ │ │ ├── titles_en_US.properties │ │ │ │ ├── errors_en_US.properties │ │ │ │ └── messages_en_US.properties │ │ │ ├── version.properties │ │ │ ├── static │ │ │ │ ├── image │ │ │ │ │ ├── app-logo.jpg │ │ │ │ │ ├── default-scope-icon.png │ │ │ │ │ └── authorization-code-client-name.png │ │ │ │ └── js │ │ │ │ │ └── jquery-util.js │ │ │ ├── templates │ │ │ │ ├── fragments │ │ │ │ │ ├── header.html │ │ │ │ │ ├── footer.html │ │ │ │ │ └── mainLayout.html │ │ │ │ ├── login.html │ │ │ │ ├── consent.html │ │ │ │ └── consent-customized.html │ │ │ ├── database │ │ │ │ └── scripts │ │ │ │ │ ├── test-data.sql │ │ │ │ │ ├── schema-h2.sql │ │ │ │ │ ├── schema-sql-server.sql │ │ │ │ │ └── schema-oauth2-sql-server.sql │ │ │ ├── oauth2-registered-client.properties │ │ │ ├── federated-identity.properties │ │ │ └── application.properties │ │ └── java │ │ │ └── pk │ │ │ └── training │ │ │ └── basit │ │ │ ├── jpa │ │ │ ├── repository │ │ │ │ └── UserPrincipalRepository.java │ │ │ ├── audit │ │ │ │ ├── AuditDeletedDate.java │ │ │ │ ├── AuditorAwareImpl.java │ │ │ │ └── Audit.java │ │ │ └── entity │ │ │ │ ├── UserAuthority.java │ │ │ │ └── UserPrincipal.java │ │ │ ├── configuration │ │ │ ├── token │ │ │ │ ├── OAuth2TokenSettings.java │ │ │ │ └── impl │ │ │ │ │ └── OAuth2TokenSettingsImpl.java │ │ │ ├── registered │ │ │ │ └── client │ │ │ │ │ ├── OAuth2RegisteredClient.java │ │ │ │ │ └── impl │ │ │ │ │ ├── PasswordOAuth2RegisteredClient.java │ │ │ │ │ ├── AbstractOAuth2RegisteredClient.java │ │ │ │ │ ├── ClientCredentialsOAuth2RegisteredClient.java │ │ │ │ │ └── AuthorizationCodeOAuth2RegisteredClient.java │ │ │ ├── JpaAuditingConfiguration.java │ │ │ ├── federated │ │ │ │ └── identity │ │ │ │ │ ├── UserRepositoryOAuth2UserHandler.java │ │ │ │ │ ├── FederatedIdentityAuthenticationSuccessHandler.java │ │ │ │ │ ├── FederatedIdentityIdTokenCustomizer.java │ │ │ │ │ ├── FederatedIdentityAuthenticationEntryPoint.java │ │ │ │ │ └── FederatedIdentityConfigurer.java │ │ │ ├── jose │ │ │ │ ├── Jwks.java │ │ │ │ └── KeyGeneratorUtils.java │ │ │ ├── OAuth2RegisteredClientConfiguration.java │ │ │ └── SecurityConfiguration.java │ │ │ ├── oauth2 │ │ │ ├── customizer │ │ │ │ ├── jwt │ │ │ │ │ ├── JwtCustomizer.java │ │ │ │ │ ├── impl │ │ │ │ │ │ ├── DefaultJwtCustomizerHandler.java │ │ │ │ │ │ ├── JwtCustomizerImpl.java │ │ │ │ │ │ ├── AbstractJwtCustomizerHandler.java │ │ │ │ │ │ ├── UsernamePasswordAuthenticationTokenJwtCustomizerHandler.java │ │ │ │ │ │ └── OAuth2AuthenticationTokenJwtCustomizerHandler.java │ │ │ │ │ └── JwtCustomizerHandler.java │ │ │ │ └── token │ │ │ │ │ └── claims │ │ │ │ │ ├── OAuth2TokenClaimsCustomizer.java │ │ │ │ │ └── impl │ │ │ │ │ └── OAuth2TokenClaimsCustomizerImpl.java │ │ │ └── authentication │ │ │ │ ├── OAuth2EndpointUtils.java │ │ │ │ ├── OAuth2ResourceOwnerPasswordAuthenticationToken.java │ │ │ │ └── OAuth2ResourceOwnerPasswordAuthenticationConverter.java │ │ │ ├── service │ │ │ ├── OAuth2RegisteredClientService.java │ │ │ ├── UserPrincipalService.java │ │ │ └── impl │ │ │ │ ├── OAuth2RegisteredClientServiceImpl.java │ │ │ │ └── UserPrincipalServiceImpl.java │ │ │ ├── SpringAuthorizationServerApplication.java │ │ │ ├── ServletInitializer.java │ │ │ ├── controller │ │ │ └── web │ │ │ │ ├── LoginController.java │ │ │ │ └── AuthorizationConsentController.java │ │ │ ├── jackson2 │ │ │ ├── mixin │ │ │ │ ├── LongMixin.java │ │ │ │ ├── AuditDeletedDateMixin.java │ │ │ │ ├── UserPrincipalMixin.java │ │ │ │ └── UserAuthorityMixin.java │ │ │ └── deserializer │ │ │ │ ├── AuditDeletedDateDeserializer.java │ │ │ │ └── UserPrincipalDeserializer.java │ │ │ └── endpoint │ │ │ └── actuator │ │ │ └── AppInfoContributor.java │ └── test │ │ └── java │ │ └── pk │ │ └── training │ │ └── basit │ │ └── test │ │ └── SpringAuthorizationServerApplicationTests.java ├── settings.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── .gitignore ├── build.gradle ├── gradlew.bat └── gradlew ├── SpringAuthorizationServerClient ├── settings.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ ├── main │ │ ├── java │ │ │ └── pk │ │ │ │ └── training │ │ │ │ └── basit │ │ │ │ ├── config │ │ │ │ ├── oauth2 │ │ │ │ │ └── client │ │ │ │ │ │ ├── OAuth2Client.java │ │ │ │ │ │ └── impl │ │ │ │ │ │ ├── AbstractOAuth2Client.java │ │ │ │ │ │ ├── OidcOAuth2Client.java │ │ │ │ │ │ ├── PasswordOAuth2Client.java │ │ │ │ │ │ ├── ClientCredentialsOAuth2Client.java │ │ │ │ │ │ └── AuthorizationCodeOAuth2Client.java │ │ │ │ ├── OAuth2ClientConfiguration.java │ │ │ │ ├── SecurityConfig.java │ │ │ │ └── WebClientConfig.java │ │ │ │ ├── SpringAuthorizationServerClientApplication.java │ │ │ │ ├── ServletInitializer.java │ │ │ │ └── controller │ │ │ │ └── web │ │ │ │ ├── IndexController.java │ │ │ │ ├── LoginController.java │ │ │ │ └── AuthorizationController.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── templates │ │ │ ├── login.html │ │ │ └── index.html │ └── test │ │ └── java │ │ └── pk │ │ └── training │ │ └── basit │ │ └── SpringAuthorizationServerClientApplicationTests.java ├── .gitignore ├── build.gradle ├── gradlew.bat └── gradlew └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.class -------------------------------------------------------------------------------- /SpringResourceServer/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'SpringResourceServer' 2 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/i18n/validation_en_US.properties: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'SpringAuthorizationServer' 2 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/version.properties: -------------------------------------------------------------------------------- 1 | release = 2022.12.04 2 | build = 7 3 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'SpringAuthorizationServerClient' 2 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/i18n/titles_en_US.properties: -------------------------------------------------------------------------------- 1 | title.app = MyApp 2 | title.login = Log In 3 | title.consent = Consent 4 | 5 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/i18n/errors_en_US.properties: -------------------------------------------------------------------------------- 1 | error.incorrect.email.password = Incorrect email and/or password. Please try again. 2 | -------------------------------------------------------------------------------- /SpringResourceServer/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Basit-Mahmood/spring-authorization-server-password-grant-type-support/HEAD/SpringResourceServer/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /SpringAuthorizationServer/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Basit-Mahmood/spring-authorization-server-password-grant-type-support/HEAD/SpringAuthorizationServer/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Basit-Mahmood/spring-authorization-server-password-grant-type-support/HEAD/SpringAuthorizationServerClient/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/static/image/app-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Basit-Mahmood/spring-authorization-server-password-grant-type-support/HEAD/SpringAuthorizationServer/src/main/resources/static/image/app-logo.jpg -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/static/image/default-scope-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Basit-Mahmood/spring-authorization-server-password-grant-type-support/HEAD/SpringAuthorizationServer/src/main/resources/static/image/default-scope-icon.png -------------------------------------------------------------------------------- /SpringResourceServer/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/static/image/authorization-code-client-name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Basit-Mahmood/spring-authorization-server-password-grant-type-support/HEAD/SpringAuthorizationServer/src/main/resources/static/image/authorization-code-client-name.png -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/templates/fragments/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 |
8 |
9 | 10 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jpa/repository/UserPrincipalRepository.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Basit-Mahmood/spring-authorization-server-password-grant-type-support/HEAD/SpringAuthorizationServer/src/main/java/pk/training/basit/jpa/repository/UserPrincipalRepository.java -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/config/oauth2/client/OAuth2Client.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.config.oauth2.client; 2 | 3 | import org.springframework.security.oauth2.client.registration.ClientRegistration; 4 | 5 | public interface OAuth2Client { 6 | 7 | ClientRegistration getClientRegistration(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/token/OAuth2TokenSettings.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.token; 2 | 3 | import org.springframework.security.oauth2.server.authorization.settings.TokenSettings; 4 | 5 | public interface OAuth2TokenSettings { 6 | 7 | TokenSettings getTokenSettings(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/templates/fragments/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/customizer/jwt/JwtCustomizer.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.customizer.jwt; 2 | 3 | import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; 4 | 5 | public interface JwtCustomizer { 6 | 7 | void customizeToken(JwtEncodingContext context); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/service/OAuth2RegisteredClientService.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.service; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; 6 | 7 | public interface OAuth2RegisteredClientService { 8 | 9 | List getOAuth2RegisteredClient(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/test/java/pk/training/basit/test/SpringAuthorizationServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | public class SpringAuthorizationServerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/test/java/pk/training/basit/SpringAuthorizationServerClientApplicationTests.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SpringAuthorizationServerClientApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /SpringResourceServer/src/test/java/pk/training/basit/SpringResourceServer/SpringResourceServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.SpringResourceServer; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SpringResourceServerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/customizer/token/claims/OAuth2TokenClaimsCustomizer.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.customizer.token.claims; 2 | 3 | import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext; 4 | 5 | public interface OAuth2TokenClaimsCustomizer { 6 | 7 | void customizeTokenClaims(OAuth2TokenClaimsContext context); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /SpringResourceServer/src/main/java/pk/training/basit/SpringResourceServerApplication.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringResourceServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringResourceServerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/SpringAuthorizationServerApplication.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringAuthorizationServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringAuthorizationServerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/SpringAuthorizationServerClientApplication.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringAuthorizationServerClientApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringAuthorizationServerClientApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/service/UserPrincipalService.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.service; 2 | 3 | import org.springframework.security.core.userdetails.UserDetailsService; 4 | import org.springframework.validation.annotation.Validated; 5 | 6 | import pk.training.basit.jpa.entity.UserPrincipal; 7 | 8 | @Validated 9 | public interface UserPrincipalService extends UserDetailsService { 10 | 11 | @Override 12 | UserPrincipal loadUserByUsername(String username); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/database/scripts/test-data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO UserPrincipal (Username, HashedPassword, AccountNonExpired, AccountNonLocked, CredentialsNonExpired, Enabled, 2 | CreatedDate, CreatedBy, UpdatedDate, UpdatedBy, DeletedDate) 3 | VALUES ( -- password 4 | 'user1', '{bcrypt}$2a$12$JG6r8yi2yHSYHNgoaQHJOeEhTS9uKavwaNWiNaEFXGVfpJU4l4MIe', 1, 1, 1, 1, 5 | CURRENT_TIMESTAMP, 0, CURRENT_TIMESTAMP, 0, null); 6 | 7 | INSERT INTO UserPrincipalAuthority (UserId, Authority) 8 | VALUES (1, 'ADMIN'), (1, 'USER'); -------------------------------------------------------------------------------- /SpringResourceServer/src/main/java/pk/training/basit/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | @Override 9 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 | return application.sources(SpringResourceServerApplication.class); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | @Override 9 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 | return application.sources(SpringAuthorizationServerApplication.class); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | @Override 9 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 | return application.sources(SpringAuthorizationServerClientApplication.class); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/i18n/messages_en_US.properties: -------------------------------------------------------------------------------- 1 | message.the.application = The application 2 | message.wants.to.access.your.app.account = wants to access your application account 3 | message.this.will.allow = This will allow 4 | message.to = to 5 | message.make.sure.you.trust = Make sure you trust 6 | 7 | button.allow = Allow 8 | button.cancel = Cancel 9 | button.login = Login 10 | 11 | placeholder.username = user1 12 | placeholder.password = password 13 | 14 | message.read.description = Read information 15 | message.write.description = Write Information 16 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/customizer/jwt/impl/DefaultJwtCustomizerHandler.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.customizer.jwt.impl; 2 | 3 | import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; 4 | 5 | import pk.training.basit.oauth2.customizer.jwt.JwtCustomizerHandler; 6 | 7 | public class DefaultJwtCustomizerHandler implements JwtCustomizerHandler { 8 | 9 | @Override 10 | public void customize(JwtEncodingContext jwtEncodingContext) { 11 | // does not modify any thing in context 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/controller/web/IndexController.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.controller.web; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | 6 | @Controller 7 | public class IndexController { 8 | 9 | // http://127.0.0.1:8080/springauthserverclient 10 | @GetMapping("/") 11 | public String root() { 12 | return "redirect:/index"; 13 | } 14 | 15 | @GetMapping("/index") 16 | public String index() { 17 | return "index"; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/registered/client/OAuth2RegisteredClient.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.registered.client; 2 | 3 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; 4 | 5 | public interface OAuth2RegisteredClient { 6 | 7 | String OAUTH2_REGISTERD_CLIENT = "oauth2.registered.client"; 8 | String ID = "id"; 9 | String NAME = "name"; 10 | String SECRET = "secret"; 11 | String REDIRECT_URI = "redirect.uri"; 12 | String SCOPE = "scope"; 13 | 14 | RegisteredClient getRegisteredClient(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/customizer/token/claims/impl/OAuth2TokenClaimsCustomizerImpl.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.customizer.token.claims.impl; 2 | 3 | import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext; 4 | 5 | import pk.training.basit.oauth2.customizer.token.claims.OAuth2TokenClaimsCustomizer; 6 | 7 | public class OAuth2TokenClaimsCustomizerImpl implements OAuth2TokenClaimsCustomizer { 8 | 9 | @Override 10 | public void customizeTokenClaims(OAuth2TokenClaimsContext context) { 11 | System.out.println(); 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /SpringResourceServer/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/controller/web/LoginController.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.controller.web; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.ui.Model; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | 7 | @Controller 8 | public class LoginController { 9 | 10 | @GetMapping("/login") 11 | public String login() { 12 | return "login"; 13 | } 14 | 15 | @GetMapping("/login-error") 16 | public String loginError(Model model) { 17 | model.addAttribute("loginError", true); 18 | return login(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/controller/web/LoginController.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.controller.web; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.ui.Model; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | 7 | @Controller 8 | public class LoginController { 9 | 10 | // http://127.0.0.1:9000/springauthserver 11 | @GetMapping("/login") 12 | public String login() { 13 | return "login"; 14 | } 15 | 16 | @GetMapping("/login-error") 17 | public String loginError(Model model) { 18 | model.addAttribute("loginError", true); 19 | return login(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/config/oauth2/client/impl/AbstractOAuth2Client.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.config.oauth2.client.impl; 2 | 3 | import org.springframework.core.env.Environment; 4 | 5 | import pk.training.basit.config.oauth2.client.OAuth2Client; 6 | 7 | public abstract class AbstractOAuth2Client implements OAuth2Client { 8 | 9 | protected String oauth2AuthorizationUri; 10 | protected String oauth2TokenUri; 11 | 12 | public AbstractOAuth2Client(Environment env) { 13 | this.oauth2AuthorizationUri = env.getProperty("oauth2.authorization.uri"); 14 | this.oauth2TokenUri = env.getProperty("oauth2.token.uri"); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/JpaAuditingConfiguration.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.domain.AuditorAware; 6 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 7 | 8 | import pk.training.basit.jpa.audit.AuditorAwareImpl; 9 | 10 | @Configuration 11 | @EnableJpaAuditing(auditorAwareRef = "auditorAware") 12 | public class JpaAuditingConfiguration { 13 | 14 | @Bean 15 | public AuditorAware auditorAware() { 16 | return new AuditorAwareImpl(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/customizer/jwt/impl/JwtCustomizerImpl.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.customizer.jwt.impl; 2 | 3 | import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; 4 | 5 | import pk.training.basit.oauth2.customizer.jwt.JwtCustomizer; 6 | import pk.training.basit.oauth2.customizer.jwt.JwtCustomizerHandler; 7 | 8 | public class JwtCustomizerImpl implements JwtCustomizer { 9 | 10 | private final JwtCustomizerHandler jwtCustomizerHandler; 11 | 12 | public JwtCustomizerImpl(JwtCustomizerHandler jwtCustomizerHandler) { 13 | this.jwtCustomizerHandler = jwtCustomizerHandler; 14 | } 15 | 16 | @Override 17 | public void customizeToken(JwtEncodingContext jwtEncodingContext) { 18 | jwtCustomizerHandler.customize(jwtEncodingContext); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jackson2/mixin/LongMixin.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.jackson2.mixin; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 6 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 7 | import com.fasterxml.jackson.databind.deser.std.NumberDeserializers.LongDeserializer; 8 | 9 | @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY) 10 | @JsonDeserialize(using = LongDeserializer.class) 11 | @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, 12 | isGetterVisibility = JsonAutoDetect.Visibility.NONE) 13 | @JsonIgnoreProperties(ignoreUnknown = true) 14 | public abstract class LongMixin { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /SpringResourceServer/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.7.15' 3 | id 'io.spring.dependency-management' version '1.0.15.RELEASE' 4 | id 'java' 5 | id 'war' 6 | } 7 | 8 | group = 'pk.training.basit' 9 | version = '0.0.1-SNAPSHOT' 10 | sourceCompatibility = '17' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | implementation 'org.springframework.boot:spring-boot-starter-web' 18 | implementation 'org.springframework.boot:spring-boot-starter-security' 19 | implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server' 20 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 21 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 22 | testImplementation 'org.springframework.security:spring-security-test' 23 | } 24 | 25 | test { 26 | useJUnitPlatform() 27 | } 28 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jackson2/mixin/AuditDeletedDateMixin.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.jackson2.mixin; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 6 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 7 | 8 | import pk.training.basit.jackson2.deserializer.AuditDeletedDateDeserializer; 9 | 10 | @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY) 11 | @JsonDeserialize(using = AuditDeletedDateDeserializer.class) 12 | @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, 13 | isGetterVisibility = JsonAutoDetect.Visibility.NONE) 14 | @JsonIgnoreProperties(ignoreUnknown = true) 15 | public class AuditDeletedDateMixin { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jackson2/mixin/UserPrincipalMixin.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.jackson2.mixin; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 6 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 7 | 8 | import pk.training.basit.jackson2.deserializer.UserPrincipalDeserializer; 9 | 10 | @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY) 11 | @JsonDeserialize(using = UserPrincipalDeserializer.class) 12 | @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, 13 | isGetterVisibility = JsonAutoDetect.Visibility.NONE) 14 | @JsonIgnoreProperties(ignoreUnknown = true) 15 | public abstract class UserPrincipalMixin { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /SpringResourceServer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.servlet.context-path = /springresourceserver 2 | server.port = 8090 3 | 4 | ################################################################### 5 | ######################## Logging ################################## 6 | ################################################################### 7 | # 8 | # This property will set the log level specifically for the org.springframework.security package. 9 | logging.level.root = INFO 10 | logging.level.org.springframework.web = INFO 11 | logging.level.org.springframework.security = INFO 12 | logging.level.org.springframework.security.oauth2 = INFO 13 | 14 | ################################################################### 15 | ######################## OAuth2 ################################## 16 | ################################################################### 17 | jwk.set.uri = http://127.0.0.1:9000/springauthserver/oauth2/jwks 18 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jackson2/mixin/UserAuthorityMixin.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.jackson2.mixin; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.JsonCreator; 5 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 6 | import com.fasterxml.jackson.annotation.JsonProperty; 7 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 8 | 9 | @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY) 10 | @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, 11 | getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY, isGetterVisibility = JsonAutoDetect.Visibility.NONE) 12 | @JsonIgnoreProperties(ignoreUnknown = true) 13 | public abstract class UserAuthorityMixin { 14 | 15 | @JsonCreator 16 | public UserAuthorityMixin(@JsonProperty("authority") String authority) { 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /SpringResourceServer/src/main/java/pk/training/basit/controller/rest/MessagesController.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.controller.rest; 2 | 3 | import org.springframework.security.access.prepost.PreAuthorize; 4 | import org.springframework.security.core.annotation.AuthenticationPrincipal; 5 | import org.springframework.security.oauth2.jwt.Jwt; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import pk.training.basit.service.JwtService; 10 | 11 | @RestController 12 | public class MessagesController { 13 | 14 | @GetMapping("/messages") 15 | @PreAuthorize("hasAuthority('USER') or hasAuthority('message.read') ") 16 | public String[] getMessages(@AuthenticationPrincipal Jwt jwt) { 17 | Long userId = JwtService.getUserId(jwt); 18 | System.out.println(userId); 19 | return new String[] {"Message 1", "Message 2", "Message 3"}; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/database/scripts/schema-h2.sql: -------------------------------------------------------------------------------- 1 | create table UserPrincipal ( 2 | UserId BIGINT auto_increment NOT NULL PRIMARY KEY, 3 | Username varchar2(36) NOT NULL, 4 | HashedPassword nvarchar2(128) NOT NULL, 5 | AccountNonExpired boolean NOT NULL, 6 | AccountNonLocked boolean NOT NULL, 7 | CredentialsNonExpired boolean NOT NULL, 8 | Enabled boolean NOT NULL, 9 | CreatedDate timestamp NOT NULL, 10 | CreatedBy BIGINT DEFAULT 0 NOT NULL, 11 | UpdatedDate timestamp, 12 | UpdatedBy BIGINT, 13 | DeletedDate timestamp, 14 | constraint UC_UserPrincipal_Username unique (Username) 15 | ); 16 | 17 | create table UserPrincipalAuthority ( 18 | UserId BIGINT NOT NULL, 19 | Authority varchar2(100) NOT NULL, 20 | constraint UC_UserPrincipalAuthority_User_Authority unique (UserId, Authority), 21 | constraint FK_UserPrincipalAuthority_UserId foreign key (UserId) 22 | references UserPrincipal (UserId) on delete cascade 23 | ); 24 | 25 | -------------------------------------------------------------------------------- /SpringResourceServer/src/main/java/pk/training/basit/service/JwtService.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.service; 2 | 3 | import org.springframework.security.oauth2.jwt.Jwt; 4 | import org.springframework.util.Assert; 5 | 6 | public interface JwtService { 7 | 8 | String USER_ID_CLAIM = "userId"; 9 | String EMAIL_CLAIM = "email"; 10 | String PRINCIPAL_USER_TYPE_CLAIM = "principalUserType"; 11 | 12 | static T getClaim(Jwt jwt, String claim, Class clazz) { 13 | 14 | Assert.notNull(jwt, "jwt cannot be null"); 15 | Assert.hasText(claim, "claim cannot be null or empty"); 16 | 17 | T value = null; 18 | 19 | if (jwt.hasClaim(claim)) { 20 | value = jwt.getClaim(claim); 21 | } 22 | 23 | return value ; 24 | } 25 | 26 | static Long getUserId(Jwt jwt) { 27 | return getClaim(jwt, USER_ID_CLAIM, Long.class); 28 | } 29 | 30 | static String getEmail(Jwt jwt) { 31 | return getClaim(jwt, EMAIL_CLAIM, String.class); 32 | } 33 | 34 | static String getPrincipalUserType(Jwt jwt) { 35 | return getClaim(jwt, PRINCIPAL_USER_TYPE_CLAIM, String.class); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.servlet.context-path = /springauthserverclient 2 | server.port = 8080 3 | 4 | ################################################################### 5 | ######################## Logging ################################## 6 | ################################################################### 7 | # 8 | # This property will set the log level specifically for the org.springframework.security package. 9 | logging.level.root = INFO 10 | logging.level.org.springframework.web = INFO 11 | logging.level.org.springframework.security = INFO 12 | logging.level.org.springframework.security.oauth2 = INFO 13 | 14 | spring.thymeleaf.cache = false 15 | 16 | messages.base-uri = http://localhost:8090/springresourceserver/messages 17 | 18 | ################################################################### 19 | ######################## OAuth2 ################################## 20 | ################################################################### 21 | oauth2.authorization.uri = http://127.0.0.1:9000/springauthserver/oauth2/authorize 22 | oauth2.token.uri = http://127.0.0.1:9000/springauthserver/oauth2/token 23 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/templates/fragments/mainLayout.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jpa/audit/AuditDeletedDate.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.jpa.audit; 2 | 3 | import java.time.Instant; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Embeddable; 7 | 8 | import org.springframework.data.annotation.AccessType; 9 | 10 | @Embeddable 11 | @AccessType(AccessType.Type.FIELD) 12 | public class AuditDeletedDate extends Audit { 13 | 14 | @Column(name = "DeletedDate") 15 | private Instant deletedDate; 16 | 17 | public AuditDeletedDate() { 18 | 19 | } 20 | 21 | public AuditDeletedDate(Audit audit, Instant deletedDate) { 22 | super(audit); 23 | this.deletedDate = deletedDate; 24 | } 25 | 26 | public AuditDeletedDate(Long createdBy, Instant createdDate, Long lastModifiedBy, Instant lastModifiedDate, Instant deletedDate) { 27 | super(createdBy, createdDate, lastModifiedBy, lastModifiedDate); 28 | this.deletedDate = deletedDate; 29 | } 30 | 31 | public Instant getDeletedDate() { 32 | return deletedDate; 33 | } 34 | 35 | public void setDeletedDate(Instant deletedDate) { 36 | this.deletedDate = deletedDate; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/config/oauth2/client/impl/OidcOAuth2Client.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.config.oauth2.client.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.security.oauth2.client.registration.ClientRegistration; 5 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | public class OidcOAuth2Client { 10 | 11 | @Value("${oauth2.token.uri}") 12 | private String oauth2TokenUri; 13 | 14 | public ClientRegistration getClientRegistration() { 15 | return ClientRegistration.withRegistrationId("messaging-client-oidc") 16 | .clientId("messaging-client") 17 | .clientSecret("secret") 18 | .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) 19 | .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}") 20 | .scope("openid") 21 | .authorizationUri("http://127.0.0.1:9000/springauthserver/connect/register") 22 | .tokenUri(oauth2TokenUri) 23 | .clientName("messaging-client-oidc") 24 | .build(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/oauth2-registered-client.properties: -------------------------------------------------------------------------------- 1 | ################################################################### 2 | ######################## OAuth2 Registered Client ################# 3 | ################################################################### 4 | oauth2.registered.client.client.credentials.id = client-credentials-client-id 5 | oauth2.registered.client.client.credentials.name = client-credentials-client-name 6 | oauth2.registered.client.client.credentials.secret = {noop}secret1 7 | oauth2.registered.client.client.credentials.scope = message.read,message.write 8 | 9 | oauth2.registered.client.authorization.code.id = authorization-code-client-id 10 | oauth2.registered.client.authorization.code.name = authorization-code-client-name 11 | oauth2.registered.client.authorization.code.secret = {noop}secret2 12 | oauth2.registered.client.authorization.code.redirect.uri = http://127.0.0.1:8080/springauthserverclient/authorized 13 | oauth2.registered.client.authorization.code.scope = message.read,message.write 14 | 15 | oauth2.registered.client.password.id = password-client-id 16 | oauth2.registered.client.password.name = password-client-name 17 | oauth2.registered.client.password.secret = {noop}secret3 18 | 19 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/customizer/jwt/JwtCustomizerHandler.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.customizer.jwt; 2 | 3 | import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; 4 | 5 | import pk.training.basit.oauth2.customizer.jwt.impl.DefaultJwtCustomizerHandler; 6 | import pk.training.basit.oauth2.customizer.jwt.impl.OAuth2AuthenticationTokenJwtCustomizerHandler; 7 | import pk.training.basit.oauth2.customizer.jwt.impl.UsernamePasswordAuthenticationTokenJwtCustomizerHandler; 8 | 9 | public interface JwtCustomizerHandler { 10 | 11 | void customize(JwtEncodingContext jwtEncodingContext); 12 | 13 | static JwtCustomizerHandler getJwtCustomizerHandler() { 14 | 15 | JwtCustomizerHandler defaultJwtCustomizerHandler = new DefaultJwtCustomizerHandler(); 16 | JwtCustomizerHandler oauth2AuthenticationTokenJwtCustomizerHandler = new OAuth2AuthenticationTokenJwtCustomizerHandler(defaultJwtCustomizerHandler); 17 | JwtCustomizerHandler usernamePasswordAuthenticationTokenJwtCustomizerHandler = new UsernamePasswordAuthenticationTokenJwtCustomizerHandler(oauth2AuthenticationTokenJwtCustomizerHandler); 18 | return usernamePasswordAuthenticationTokenJwtCustomizerHandler; 19 | 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/static/js/jquery-util.js: -------------------------------------------------------------------------------- 1 | let $currentAccordianRow = null; 2 | 3 | function findHiddenFieldInForm($form, hiddenFieldId, hiddenFieldName, hiddenFieldValue) { 4 | 5 | //let $formHiddenField = $form.find("input[type='hidden'][id='" + hiddenFieldId + "'][name='" + hiddenFieldName + "']"); 6 | let $formHiddenField = $form.find("input[type='hidden'][name='" + hiddenFieldName + "']"); 7 | if ($formHiddenField.length >= 1) { 8 | return $formHiddenField; 9 | } 10 | return null; 11 | } 12 | 13 | function addHiddenFieldToForm($form, hiddenFieldId, hiddenFieldName, hiddenFieldValue) { 14 | 15 | let $formHiddenField = findHiddenFieldInForm($form, hiddenFieldId, hiddenFieldName, hiddenFieldValue); 16 | if ($formHiddenField == null) { 17 | jQuery('', { 18 | type: 'hidden', 19 | id: hiddenFieldId, 20 | name: hiddenFieldName, 21 | value: hiddenFieldValue 22 | }).appendTo($form); 23 | } 24 | } 25 | 26 | function removeHiddenFieldFromForm($form, hiddenFieldId, hiddenFieldName, hiddenFieldValue) { 27 | 28 | var $formHiddenField = findHiddenFieldInForm($form, hiddenFieldId, hiddenFieldName, hiddenFieldValue); 29 | if ($formHiddenField != null) { 30 | $formHiddenField.remove(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jpa/audit/AuditorAwareImpl.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.jpa.audit; 2 | 3 | import java.util.Optional; 4 | 5 | import org.springframework.data.domain.AuditorAware; 6 | import org.springframework.security.authentication.AnonymousAuthenticationToken; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.core.context.SecurityContextHolder; 9 | 10 | import pk.training.basit.jpa.entity.UserPrincipal; 11 | 12 | public class AuditorAwareImpl implements AuditorAware { 13 | 14 | @Override 15 | public Optional getCurrentAuditor() { 16 | 17 | Long userId = 0L; 18 | 19 | Authentication principal = SecurityContextHolder.getContext().getAuthentication(); 20 | if (isPrincipalAuthenticated(principal)) { 21 | UserPrincipal userPrincipal = (UserPrincipal) principal.getPrincipal(); 22 | userId = userPrincipal.getId(); 23 | } 24 | 25 | return Optional.of(userId); 26 | } 27 | 28 | private static boolean isPrincipalAuthenticated(Authentication principal) { 29 | return principal != null && 30 | !AnonymousAuthenticationToken.class.isAssignableFrom(principal.getClass()) && principal.isAuthenticated(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/config/oauth2/client/impl/PasswordOAuth2Client.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.config.oauth2.client.impl; 2 | 3 | import org.springframework.core.env.Environment; 4 | import org.springframework.security.oauth2.client.registration.ClientRegistration; 5 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 6 | import org.springframework.security.oauth2.core.ClientAuthenticationMethod; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class PasswordOAuth2Client extends AbstractOAuth2Client { 11 | 12 | public PasswordOAuth2Client(Environment env) { 13 | super(env); 14 | } 15 | 16 | @Override 17 | public ClientRegistration getClientRegistration() { 18 | return ClientRegistration.withRegistrationId("password-client-name") 19 | .clientId("password-client-id") 20 | .clientSecret("secret3") 21 | .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST) 22 | .authorizationGrantType(AuthorizationGrantType.PASSWORD) 23 | //.scope("message.read", "message.write") 24 | .authorizationUri(oauth2AuthorizationUri) 25 | .tokenUri(oauth2TokenUri) 26 | .build(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/federated-identity.properties: -------------------------------------------------------------------------------- 1 | 2 | idp.login.enable = true 3 | 4 | spring.security.oauth2.client.provider.google.user-name-attribute = email 5 | spring.security.oauth2.client.registration.google-idp.provider = google 6 | spring.security.oauth2.client.registration.google-idp.client-id = ${GOOGLE_CLIENT_ID:google-client-id} 7 | spring.security.oauth2.client.registration.google-idp.client-secret = ${GOOGLE_CLIENT_SECRET:google-client-secret} 8 | spring.security.oauth2.client.registration.google-idp.scope = openid, https://www.googleapis.com/auth/userinfo.profile, https://www.googleapis.com/auth/userinfo.email 9 | spring.security.oauth2.client.registration.google-idp.client-name = Sign in with Google 10 | 11 | spring.security.oauth2.client.provider.github.user-name-attribute = login 12 | spring.security.oauth2.client.registration.github-idp.provider = github 13 | spring.security.oauth2.client.registration.github-idp.client-id = ${GITHUB_CLIENT_ID:github-client-id} 14 | spring.security.oauth2.client.registration.github-idp.client-secret = ${GITHUB_CLIENT_SECRET:github-client-secret} 15 | spring.security.oauth2.client.registration.github-idp.scope = user:email, read:user 16 | spring.security.oauth2.client.registration.github-idp.client-name = Sign in with GitHub 17 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/federated/identity/UserRepositoryOAuth2UserHandler.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.federated.identity; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | import java.util.function.Consumer; 6 | 7 | import org.springframework.security.oauth2.core.user.OAuth2User; 8 | 9 | public class UserRepositoryOAuth2UserHandler implements Consumer { 10 | 11 | private final UserRepository userRepository = new UserRepository(); 12 | 13 | @Override 14 | public void accept(OAuth2User user) { 15 | // Capture user in a local data store on first authentication 16 | if (this.userRepository.findByName(user.getName()) == null) { 17 | System.out.println("Saving first-time user: name=" + user.getName() + ", claims=" + user.getAttributes() + ", authorities=" + user.getAuthorities()); 18 | this.userRepository.save(user); 19 | } 20 | } 21 | 22 | static class UserRepository { 23 | 24 | private final Map userCache = new ConcurrentHashMap<>(); 25 | 26 | public OAuth2User findByName(String name) { 27 | return this.userCache.get(name); 28 | } 29 | 30 | public void save(OAuth2User oauth2User) { 31 | this.userCache.put(oauth2User.getName(), oauth2User); 32 | } 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/endpoint/actuator/AppInfoContributor.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.endpoint.actuator; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | 6 | import org.apache.logging.log4j.LogManager; 7 | import org.apache.logging.log4j.Logger; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.boot.actuate.info.Info.Builder; 10 | import org.springframework.boot.actuate.info.InfoContributor; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | public class AppInfoContributor implements InfoContributor { 15 | 16 | private static final Logger LOGGER = LogManager.getLogger(AppInfoContributor.class); 17 | 18 | private final Map appInfoMap = new LinkedHashMap<>(); 19 | 20 | public AppInfoContributor(@Value("${release}") String release, @Value("${build}")String build) { 21 | LOGGER.debug("in AppInfoContributor release=" + release + " build=" + build); 22 | appInfoMap.put("release", release); 23 | appInfoMap.put("build", build); 24 | } 25 | 26 | // http://127.0.0.1:9000/springauthserver/actuator/info 27 | @Override 28 | public void contribute(Builder builder) { 29 | LOGGER.debug("in contribute"); 30 | builder.withDetails(appInfoMap); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/config/oauth2/client/impl/ClientCredentialsOAuth2Client.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.config.oauth2.client.impl; 2 | 3 | import org.springframework.core.env.Environment; 4 | import org.springframework.security.oauth2.client.registration.ClientRegistration; 5 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 6 | import org.springframework.security.oauth2.core.ClientAuthenticationMethod; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class ClientCredentialsOAuth2Client extends AbstractOAuth2Client { 11 | 12 | public ClientCredentialsOAuth2Client(Environment env) { 13 | super(env); 14 | } 15 | 16 | @Override 17 | public ClientRegistration getClientRegistration() { 18 | return ClientRegistration.withRegistrationId("client-credentials-client-name") 19 | .clientId("client-credentials-client-id") 20 | .clientSecret("secret1") 21 | .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) 22 | .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) 23 | .scope("message.read", "message.write") 24 | .authorizationUri(oauth2AuthorizationUri) 25 | .tokenUri(oauth2TokenUri) 26 | .build(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/config/OAuth2ClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.config; 2 | 3 | import java.util.List; 4 | import java.util.stream.Collectors; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.security.oauth2.client.registration.ClientRegistration; 10 | import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; 11 | import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; 12 | 13 | import pk.training.basit.config.oauth2.client.OAuth2Client; 14 | 15 | @Configuration 16 | public class OAuth2ClientConfiguration { 17 | 18 | @Autowired 19 | private List oauth2Clients; 20 | 21 | @Bean 22 | public ClientRegistrationRepository clientRegistrationRepository() { 23 | 24 | List registrations = oauth2Clients.stream() 25 | .map(c -> c.getClientRegistration()) 26 | .filter(registration -> registration != null) 27 | .collect(Collectors.toList()); 28 | 29 | return new InMemoryClientRegistrationRepository(registrations); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.7.15' 3 | id 'io.spring.dependency-management' version '1.0.15.RELEASE' 4 | id 'java' 5 | id 'war' 6 | } 7 | 8 | group = 'pk.training.basit' 9 | version = '0.0.1-SNAPSHOT' 10 | sourceCompatibility = '17' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | implementation 'org.springframework.boot:spring-boot-starter-web' 18 | implementation 'org.springframework.boot:spring-boot-starter-webflux' 19 | implementation 'org.springframework.boot:spring-boot-starter-security' 20 | implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' 21 | implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' 22 | implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' 23 | implementation group: 'org.webjars', name: 'webjars-locator', version: '0.47' 24 | implementation group: 'org.webjars', name: 'bootstrap', version: '5.3.1' 25 | implementation group: 'org.webjars', name: 'jquery', version: '3.7.1' 26 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 27 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 28 | testImplementation 'io.projectreactor:reactor-test' 29 | testImplementation 'org.springframework.security:spring-security-test' 30 | } 31 | 32 | test { 33 | useJUnitPlatform() 34 | } 35 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/config/oauth2/client/impl/AuthorizationCodeOAuth2Client.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.config.oauth2.client.impl; 2 | 3 | import org.springframework.core.env.Environment; 4 | import org.springframework.security.oauth2.client.registration.ClientRegistration; 5 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 6 | import org.springframework.security.oauth2.core.ClientAuthenticationMethod; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class AuthorizationCodeOAuth2Client extends AbstractOAuth2Client { 11 | 12 | public AuthorizationCodeOAuth2Client(Environment env) { 13 | super(env); 14 | } 15 | 16 | @Override 17 | public ClientRegistration getClientRegistration() { 18 | return ClientRegistration.withRegistrationId("authorization-code-client-name") 19 | .clientId("authorization-code-client-id") 20 | .clientSecret("secret2") 21 | .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST) 22 | .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) 23 | .redirectUri("{baseUrl}/authorized") 24 | .scope("message.read", "message.write") 25 | .authorizationUri(oauth2AuthorizationUri) 26 | .tokenUri(oauth2TokenUri) 27 | .build(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/database/scripts/schema-sql-server.sql: -------------------------------------------------------------------------------- 1 | IF NOT EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME = 'UserPrincipal' AND XTYPE='U') 2 | BEGIN TRY 3 | -- SCHEMA 4 | CREATE TABLE UserPrincipal ( 5 | UserId BIGINT NOT NULL IDENTITY PRIMARY KEY, 6 | Username VARCHAR(36) NOT NULL, 7 | HashedPassword VARCHAR(128) NOT NULL, 8 | AccountNonExpired BIT NOT NULL, 9 | AccountNonLocked BIT NOT NULL, 10 | CredentialsNonExpired BIT NOT NULL, 11 | Enabled BIT NOT NULL, 12 | CreatedDate DATETIME NOT NULL, 13 | CreatedBy BIGINT DEFAULT 0 NOT NULL, 14 | UpdatedDate DATETIME, 15 | UpdatedBy BIGINT, 16 | DeletedDate DATETIME, 17 | CONSTRAINT UC_UserPrincipal_Username UNIQUE (Username) 18 | ) 19 | END TRY 20 | BEGIN CATCH 21 | SELECT ERROR_MESSAGE() AS 'UserPrincipal Message' 22 | END CATCH 23 | 24 | IF NOT EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME = 'UserPrincipalAuthority' AND XTYPE='U') 25 | BEGIN TRY 26 | -- SCHEMA 27 | CREATE TABLE UserPrincipalAuthority ( 28 | UserId BIGINT NOT NULL, 29 | Authority VARCHAR(100) NOT NULL, 30 | CONSTRAINT UC_UserPrincipalAuthority_User_Authority UNIQUE (UserId, Authority), 31 | CONSTRAINT FK_UserPrincipalAuthority_UserId FOREIGN KEY (UserId) 32 | REFERENCES UserPrincipal (UserId) ON DELETE CASCADE 33 | ) 34 | END TRY 35 | BEGIN CATCH 36 | SELECT ERROR_MESSAGE() AS 'UserPrincipalAuthority Message' 37 | END CATCH 38 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/service/impl/OAuth2RegisteredClientServiceImpl.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.service.impl; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.util.CollectionUtils; 10 | 11 | import pk.training.basit.configuration.registered.client.OAuth2RegisteredClient; 12 | import pk.training.basit.service.OAuth2RegisteredClientService; 13 | 14 | @Service 15 | public class OAuth2RegisteredClientServiceImpl implements OAuth2RegisteredClientService { 16 | 17 | private final List inMemoryOAuth2RegisteredClients; 18 | 19 | public OAuth2RegisteredClientServiceImpl(List oauth2RegisteredClients) { 20 | this.inMemoryOAuth2RegisteredClients = oauth2RegisteredClients; 21 | } 22 | 23 | @Override 24 | public List getOAuth2RegisteredClient() { 25 | 26 | List registeredClients = Collections.emptyList(); 27 | if (!CollectionUtils.isEmpty(inMemoryOAuth2RegisteredClients)) { 28 | registeredClients = inMemoryOAuth2RegisteredClients.stream() 29 | .map(oauth2RegisteredClient -> oauth2RegisteredClient.getRegisteredClient()) 30 | .collect(Collectors.toList()); 31 | } 32 | 33 | return registeredClients; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jpa/entity/UserAuthority.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.jpa.entity; 2 | 3 | import javax.persistence.Embeddable; 4 | 5 | import org.springframework.security.core.GrantedAuthority; 6 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 7 | import org.springframework.util.Assert; 8 | 9 | /** 10 | * The UserAuthority class is simple: It's just an embeddable POJO that implements GrantedAuthority. 11 | */ 12 | @Embeddable 13 | public class UserAuthority implements GrantedAuthority { 14 | 15 | private static final long serialVersionUID = 1L; 16 | 17 | private String authority; 18 | 19 | public UserAuthority() { 20 | } 21 | 22 | public UserAuthority(String authority) { 23 | Assert.hasText(authority, "A granted authority textual representation is required"); 24 | this.authority = authority; 25 | } 26 | 27 | @Override 28 | public String getAuthority() { 29 | return this.authority; 30 | } 31 | 32 | public void setAuthority(String authority) { 33 | this.authority = authority; 34 | } 35 | 36 | @Override 37 | public boolean equals(Object obj) { 38 | if (this == obj) { 39 | return true; 40 | } 41 | if (obj instanceof SimpleGrantedAuthority) { 42 | return this.authority.equals(((UserAuthority) obj).authority); 43 | } 44 | return false; 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | return this.authority.hashCode(); 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return this.authority; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/jose/Jwks.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.jose; 2 | 3 | import java.security.KeyPair; 4 | import java.security.interfaces.ECPrivateKey; 5 | import java.security.interfaces.ECPublicKey; 6 | import java.security.interfaces.RSAPrivateKey; 7 | import java.security.interfaces.RSAPublicKey; 8 | import java.util.UUID; 9 | 10 | import javax.crypto.SecretKey; 11 | 12 | import com.nimbusds.jose.jwk.Curve; 13 | import com.nimbusds.jose.jwk.ECKey; 14 | import com.nimbusds.jose.jwk.OctetSequenceKey; 15 | import com.nimbusds.jose.jwk.RSAKey; 16 | 17 | public final class Jwks { 18 | 19 | private Jwks() { 20 | } 21 | 22 | public static RSAKey generateRsa() { 23 | KeyPair keyPair = KeyGeneratorUtils.generateRsaKey(); 24 | RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); 25 | RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); 26 | 27 | return new RSAKey.Builder(publicKey) 28 | .privateKey(privateKey) 29 | .keyID(UUID.randomUUID().toString()) 30 | .build(); 31 | } 32 | 33 | public static ECKey generateEc() { 34 | KeyPair keyPair = KeyGeneratorUtils.generateEcKey(); 35 | ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic(); 36 | ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate(); 37 | Curve curve = Curve.forECParameterSpec(publicKey.getParams()); 38 | 39 | return new ECKey.Builder(curve, publicKey) 40 | .privateKey(privateKey) 41 | .keyID(UUID.randomUUID().toString()) 42 | .build(); 43 | } 44 | 45 | public static OctetSequenceKey generateSecret() { 46 | 47 | SecretKey secretKey = KeyGeneratorUtils.generateSecretKey(); 48 | return new OctetSequenceKey.Builder(secretKey) 49 | .keyID(UUID.randomUUID().toString()) 50 | .build(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.7.15' 3 | id 'io.spring.dependency-management' version '1.0.15.RELEASE' 4 | id 'java' 5 | id 'war' 6 | } 7 | 8 | group = 'pk.training.basit' 9 | version = '0.0.1-SNAPSHOT' 10 | sourceCompatibility = '17' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | ext { 17 | webjarsGroupId = "org.webjars" 18 | } 19 | 20 | dependencies { 21 | implementation 'org.springframework.boot:spring-boot-starter-web' 22 | implementation 'org.springframework.boot:spring-boot-starter-security' 23 | implementation 'org.springframework.boot:spring-boot-starter-jdbc' 24 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 25 | implementation 'org.springframework.boot:spring-boot-starter-actuator' 26 | implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' 27 | implementation 'org.springframework.security:spring-security-oauth2-authorization-server:0.4.3' 28 | implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' 29 | implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' 30 | implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect' 31 | implementation group: webjarsGroupId, name: 'webjars-locator', version: '0.47' 32 | implementation group: webjarsGroupId, name: 'bootstrap', version: '5.3.1' 33 | implementation group: webjarsGroupId, name: 'jquery', version: '3.7.1' 34 | //runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc' 35 | runtimeOnly 'com.h2database:h2' 36 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 37 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 38 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 39 | testImplementation 'org.springframework.security:spring-security-test' 40 | } 41 | 42 | test { 43 | useJUnitPlatform() 44 | } 45 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/OAuth2RegisteredClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.logging.log4j.LogManager; 6 | import org.apache.logging.log4j.Logger; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.context.annotation.PropertySource; 11 | import org.springframework.jdbc.core.JdbcTemplate; 12 | import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository; 13 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; 14 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; 15 | 16 | import pk.training.basit.service.OAuth2RegisteredClientService; 17 | 18 | @Configuration 19 | @PropertySource("classpath:oauth2-registered-client.properties") 20 | public class OAuth2RegisteredClientConfiguration { 21 | 22 | private static final Logger LOGGER = LogManager.getLogger(OAuth2RegisteredClientConfiguration.class); 23 | 24 | @Autowired 25 | private OAuth2RegisteredClientService oauth2RegisteredClientService; 26 | 27 | @Bean 28 | public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) { 29 | 30 | LOGGER.debug("in registeredClientRepository"); 31 | 32 | List registeredClients = oauth2RegisteredClientService.getOAuth2RegisteredClient(); 33 | 34 | JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate); 35 | registeredClients.forEach(registeredClient -> { 36 | registeredClientRepository.save(registeredClient); 37 | }); 38 | 39 | return registeredClientRepository; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Spring Security OAuth 2.0 Sample 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |

Login

13 |

Wrong username or password

14 |
15 |
16 |
17 | 18 | 19 | user1 / password 20 |
21 |
22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 |
30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/authentication/OAuth2EndpointUtils.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.authentication; 2 | 3 | import java.util.Map; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | 7 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 8 | import org.springframework.security.oauth2.core.OAuth2AuthenticationException; 9 | import org.springframework.security.oauth2.core.OAuth2Error; 10 | import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; 11 | import org.springframework.security.oauth2.core.endpoint.PkceParameterNames; 12 | import org.springframework.util.LinkedMultiValueMap; 13 | import org.springframework.util.MultiValueMap; 14 | 15 | public class OAuth2EndpointUtils { 16 | 17 | static final String ACCESS_TOKEN_REQUEST_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2"; 18 | 19 | private OAuth2EndpointUtils() { 20 | } 21 | 22 | public static MultiValueMap getParameters(HttpServletRequest request) { 23 | Map parameterMap = request.getParameterMap(); 24 | MultiValueMap parameters = new LinkedMultiValueMap<>(parameterMap.size()); 25 | parameterMap.forEach((key, values) -> { 26 | if (values.length > 0) { 27 | for (String value : values) { 28 | parameters.add(key, value); 29 | } 30 | } 31 | }); 32 | return parameters; 33 | } 34 | 35 | public static boolean matchesPkceTokenRequest(HttpServletRequest request) { 36 | return AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals( 37 | request.getParameter(OAuth2ParameterNames.GRANT_TYPE)) && 38 | request.getParameter(OAuth2ParameterNames.CODE) != null && 39 | request.getParameter(PkceParameterNames.CODE_VERIFIER) != null; 40 | } 41 | 42 | public static void throwError(String errorCode, String parameterName, String errorUri) { 43 | OAuth2Error error = new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName, errorUri); 44 | throw new OAuth2AuthenticationException(error); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.config; 2 | 3 | import static org.springframework.security.config.Customizer.withDefaults; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Bean; 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.EnableWebSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; 11 | import org.springframework.security.core.userdetails.User; 12 | import org.springframework.security.core.userdetails.UserDetails; 13 | import org.springframework.security.core.userdetails.UserDetailsService; 14 | import org.springframework.security.provisioning.InMemoryUserDetailsManager; 15 | import org.springframework.security.web.SecurityFilterChain; 16 | 17 | @EnableWebSecurity 18 | public class SecurityConfig { 19 | 20 | @Autowired 21 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 22 | auth.eraseCredentials(false); 23 | } 24 | 25 | @Bean 26 | SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 27 | http.authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated()) 28 | .formLogin(form -> form.loginPage("/login").failureUrl("/login-error").permitAll()) 29 | .oauth2Client(withDefaults()); 30 | 31 | return http.build(); 32 | } 33 | 34 | @Bean 35 | WebSecurityCustomizer webSecurityCustomizer() { 36 | return (web) -> web.ignoring().antMatchers("/webjars/**"); 37 | } 38 | 39 | @Bean 40 | UserDetailsService users() { 41 | 42 | UserDetails user = User.withDefaultPasswordEncoder() 43 | .username("user1") 44 | .password("password") 45 | .authorities("USER") 46 | .build(); 47 | 48 | return new InMemoryUserDetailsManager(user); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/customizer/jwt/impl/AbstractJwtCustomizerHandler.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.customizer.jwt.impl; 2 | 3 | import org.springframework.security.authentication.AbstractAuthenticationToken; 4 | import org.springframework.security.core.Authentication; 5 | import org.springframework.security.core.context.SecurityContextHolder; 6 | import org.springframework.security.oauth2.server.authorization.OAuth2TokenType; 7 | import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken; 8 | import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; 9 | 10 | import pk.training.basit.oauth2.customizer.jwt.JwtCustomizerHandler; 11 | 12 | public abstract class AbstractJwtCustomizerHandler implements JwtCustomizerHandler { 13 | 14 | protected JwtCustomizerHandler jwtCustomizerHandler; 15 | 16 | public AbstractJwtCustomizerHandler(JwtCustomizerHandler jwtCustomizerHandler) { 17 | this.jwtCustomizerHandler = jwtCustomizerHandler; 18 | } 19 | 20 | protected abstract boolean supportCustomizeContext(Authentication authentication); 21 | protected abstract void customizeJwt(JwtEncodingContext jwtEncodingContext); 22 | 23 | @Override 24 | public void customize(JwtEncodingContext jwtEncodingContext) { 25 | 26 | boolean supportCustomizeContext = false; 27 | AbstractAuthenticationToken token = null; 28 | 29 | Authentication authenticataion = SecurityContextHolder.getContext().getAuthentication(); 30 | 31 | if (authenticataion instanceof OAuth2ClientAuthenticationToken ) { 32 | token = (OAuth2ClientAuthenticationToken) authenticataion; 33 | } 34 | 35 | if (token != null) { 36 | if (token.isAuthenticated() && OAuth2TokenType.ACCESS_TOKEN.equals(jwtEncodingContext.getTokenType())) { 37 | Authentication authentication = jwtEncodingContext.getPrincipal(); 38 | supportCustomizeContext = supportCustomizeContext(authentication); 39 | } 40 | } 41 | 42 | if (supportCustomizeContext) { 43 | customizeJwt(jwtEncodingContext); 44 | } else { 45 | jwtCustomizerHandler.customize(jwtEncodingContext); 46 | } 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/federated/identity/FederatedIdentityAuthenticationSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.federated.identity; 2 | 3 | import java.io.IOException; 4 | import java.util.function.Consumer; 5 | 6 | import javax.servlet.ServletException; 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | 10 | import org.springframework.security.core.Authentication; 11 | import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; 12 | import org.springframework.security.oauth2.core.oidc.user.OidcUser; 13 | import org.springframework.security.oauth2.core.user.OAuth2User; 14 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 15 | import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; 16 | 17 | public final class FederatedIdentityAuthenticationSuccessHandler implements AuthenticationSuccessHandler { 18 | 19 | private final AuthenticationSuccessHandler delegate = new SavedRequestAwareAuthenticationSuccessHandler(); 20 | 21 | private Consumer oauth2UserHandler = (user) -> {}; 22 | 23 | private Consumer oidcUserHandler = (user) -> this.oauth2UserHandler.accept(user); 24 | 25 | @Override 26 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 27 | if (authentication instanceof OAuth2AuthenticationToken) { 28 | if (authentication.getPrincipal() instanceof OidcUser) { 29 | this.oidcUserHandler.accept((OidcUser) authentication.getPrincipal()); 30 | } else if (authentication.getPrincipal() instanceof OAuth2User) { 31 | this.oauth2UserHandler.accept((OAuth2User) authentication.getPrincipal()); 32 | } 33 | } 34 | 35 | this.delegate.onAuthenticationSuccess(request, response, authentication); 36 | } 37 | 38 | public void setOAuth2UserHandler(Consumer oauth2UserHandler) { 39 | this.oauth2UserHandler = oauth2UserHandler; 40 | } 41 | 42 | public void setOidcUserHandler(Consumer oidcUserHandler) { 43 | this.oidcUserHandler = oidcUserHandler; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jackson2/deserializer/AuditDeletedDateDeserializer.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.jackson2.deserializer; 2 | 3 | import java.io.IOException; 4 | import java.time.Instant; 5 | 6 | import com.fasterxml.jackson.core.JsonParser; 7 | import com.fasterxml.jackson.core.JsonProcessingException; 8 | import com.fasterxml.jackson.core.type.TypeReference; 9 | import com.fasterxml.jackson.databind.DeserializationContext; 10 | import com.fasterxml.jackson.databind.JsonDeserializer; 11 | import com.fasterxml.jackson.databind.JsonNode; 12 | import com.fasterxml.jackson.databind.ObjectMapper; 13 | import com.fasterxml.jackson.databind.node.MissingNode; 14 | 15 | import pk.training.basit.jpa.audit.Audit; 16 | import pk.training.basit.jpa.audit.AuditDeletedDate; 17 | 18 | public class AuditDeletedDateDeserializer extends JsonDeserializer { 19 | 20 | private static final TypeReference INSTANT = new TypeReference() {}; 21 | 22 | @Override 23 | public AuditDeletedDate deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 24 | 25 | ObjectMapper mapper = (ObjectMapper) jp.getCodec(); 26 | JsonNode jsonNode = mapper.readTree(jp); 27 | Long createdBy = readJsonNode(jsonNode, "createdBy").asLong(); 28 | Long lastModifiedBy = readJsonNode(jsonNode, "lastModifiedBy").asLong(); 29 | JsonNode createdDateNode = readJsonNode(jsonNode, "createdDate"); 30 | JsonNode lastModifiedDateNode = readJsonNode(jsonNode, "lastModifiedDate"); 31 | JsonNode deletedDateNode = readJsonNode(jsonNode, "deletedDate"); 32 | 33 | Instant createdDate = mapper.readValue(createdDateNode.toString(), INSTANT); 34 | Instant lastModifiedDate = mapper.readValue(lastModifiedDateNode.toString(), INSTANT); 35 | Instant deletedDate = mapper.readValue(deletedDateNode.toString(), INSTANT); 36 | 37 | Audit audit = new Audit(createdBy, createdDate, lastModifiedBy, lastModifiedDate); 38 | AuditDeletedDate auditDeletedDate = new AuditDeletedDate(audit, deletedDate); 39 | 40 | return auditDeletedDate; 41 | 42 | } 43 | 44 | private JsonNode readJsonNode(JsonNode jsonNode, String field) { 45 | return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /SpringResourceServer/src/main/java/pk/training/basit/configuration/ResourceServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 8 | import org.springframework.security.oauth2.jwt.JwtDecoder; 9 | import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; 10 | import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; 11 | import org.springframework.security.web.SecurityFilterChain; 12 | 13 | import pk.training.basit.converter.jwt.CustomJwtGrantedAuthoritiesConverter; 14 | 15 | @EnableGlobalMethodSecurity( 16 | prePostEnabled = true, 17 | order = 0 18 | ) 19 | @EnableWebSecurity 20 | public class ResourceServerConfiguration { 21 | 22 | @Value("${jwk.set.uri}") 23 | private String jwkSetUri; 24 | 25 | @Bean 26 | public JwtDecoder jwtDecoder() { 27 | return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build(); 28 | } 29 | 30 | JwtAuthenticationConverter jwtAuthenticationConverter() { 31 | CustomJwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new CustomJwtGrantedAuthoritiesConverter(); 32 | grantedAuthoritiesConverter.setAuthorityPrefix(""); 33 | 34 | JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter(); 35 | jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter); 36 | return jwtAuthenticationConverter; 37 | } 38 | 39 | @Bean 40 | SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 41 | http.mvcMatcher("/messages/**").authorizeRequests() 42 | .anyRequest().authenticated() 43 | //.mvcMatchers("/messages/**").access("hasAuthority('USER')") 44 | .and() 45 | .oauth2ResourceServer(oauth2 -> oauth2 46 | .jwt(jwt -> jwt.decoder(jwtDecoder()).jwtAuthenticationConverter(jwtAuthenticationConverter())) 47 | ); 48 | 49 | return http.build(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/registered/client/impl/PasswordOAuth2RegisteredClient.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.registered.client.impl; 2 | 3 | import org.apache.logging.log4j.LogManager; 4 | import org.apache.logging.log4j.Logger; 5 | import org.springframework.core.env.Environment; 6 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 7 | import org.springframework.security.oauth2.core.ClientAuthenticationMethod; 8 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; 9 | import org.springframework.stereotype.Component; 10 | 11 | import pk.training.basit.configuration.token.OAuth2TokenSettings; 12 | 13 | @Component 14 | public class PasswordOAuth2RegisteredClient extends AbstractOAuth2RegisteredClient { 15 | 16 | private static final Logger LOGGER = LogManager.getLogger(PasswordOAuth2RegisteredClient.class); 17 | 18 | private static final String PASSWORD_CLIENT = "password"; 19 | 20 | public PasswordOAuth2RegisteredClient(Environment env, OAuth2TokenSettings oauth2TokenSettings) { 21 | super(env, oauth2TokenSettings); 22 | LOGGER.debug("In PasswordOAuth2RegisteredClient"); 23 | } 24 | 25 | @Override 26 | public RegisteredClient getRegisteredClient() { 27 | 28 | LOGGER.debug("In PasswordOAuth2RegisteredClient.getRegisteredClient()"); 29 | 30 | RegisteredClient.Builder registeredClientBuilder = getRegisteredClientBuilder(); 31 | RegisteredClient passwordRegisteredClient = registeredClientBuilder.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST) 32 | .authorizationGrantType(AuthorizationGrantType.PASSWORD) 33 | .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) 34 | .build(); 35 | 36 | return passwordRegisteredClient; 37 | 38 | } 39 | 40 | @Override 41 | public String getId() { 42 | return "3"; 43 | } 44 | 45 | @Override 46 | public String getClientId() { 47 | String passwordClientId = getClientProperty(PASSWORD_CLIENT, ID); 48 | return passwordClientId; 49 | } 50 | 51 | @Override 52 | public String getClientName() { 53 | String passwordClientName = getClientProperty(PASSWORD_CLIENT, NAME); 54 | return passwordClientName; 55 | } 56 | 57 | @Override 58 | public String getClientSecret() { 59 | String passwordClientSecret = getClientProperty(PASSWORD_CLIENT, SECRET); 60 | return passwordClientSecret; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/registered/client/impl/AbstractOAuth2RegisteredClient.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.registered.client.impl; 2 | 3 | import org.apache.logging.log4j.LogManager; 4 | import org.apache.logging.log4j.Logger; 5 | import org.springframework.core.env.Environment; 6 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; 7 | import org.springframework.security.oauth2.server.authorization.settings.TokenSettings; 8 | 9 | import pk.training.basit.configuration.registered.client.OAuth2RegisteredClient; 10 | import pk.training.basit.configuration.token.OAuth2TokenSettings; 11 | 12 | public abstract class AbstractOAuth2RegisteredClient implements OAuth2RegisteredClient { 13 | 14 | private static final Logger LOGGER = LogManager.getLogger(AbstractOAuth2RegisteredClient.class); 15 | 16 | protected final Environment env; 17 | protected final OAuth2TokenSettings oauth2TokenSettings; 18 | 19 | protected AbstractOAuth2RegisteredClient(Environment env, OAuth2TokenSettings oauth2TokenSettings) { 20 | this.env = env; 21 | this.oauth2TokenSettings = oauth2TokenSettings; 22 | } 23 | 24 | protected abstract String getId(); 25 | protected abstract String getClientId(); 26 | protected abstract String getClientName(); 27 | protected abstract String getClientSecret(); 28 | 29 | protected String getClientProperty(String client, String property) { 30 | 31 | LOGGER.debug("in getClientProperty"); 32 | 33 | // oauth2.registered.client.authorization.code.id 34 | String propertyName = String.format("%s.%s.%s", OAUTH2_REGISTERD_CLIENT, client, property); 35 | String propertyValue = env.getProperty(propertyName); 36 | return propertyValue; 37 | } 38 | 39 | protected TokenSettings getTokenSettings() { 40 | return oauth2TokenSettings.getTokenSettings(); 41 | } 42 | 43 | protected RegisteredClient.Builder getRegisteredClientBuilder() { 44 | 45 | String id = getId(); 46 | String clientId = getClientId(); 47 | String clientName = getClientName();; 48 | String clientSecret = getClientSecret(); 49 | 50 | TokenSettings tokenSetting = getTokenSettings(); 51 | 52 | RegisteredClient.Builder registeredClientBuilder = RegisteredClient.withId(id) 53 | .clientId(clientId) 54 | .clientName(clientName) 55 | .clientSecret(clientSecret) 56 | .tokenSettings(tokenSetting); 57 | 58 | return registeredClientBuilder; 59 | 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jpa/audit/Audit.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.jpa.audit; 2 | 3 | import java.time.Instant; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Embeddable; 7 | import javax.persistence.MappedSuperclass; 8 | 9 | import org.springframework.data.annotation.AccessType; 10 | import org.springframework.data.annotation.CreatedBy; 11 | import org.springframework.data.annotation.CreatedDate; 12 | import org.springframework.data.annotation.LastModifiedBy; 13 | import org.springframework.data.annotation.LastModifiedDate; 14 | 15 | @MappedSuperclass 16 | @Embeddable 17 | @AccessType(AccessType.Type.FIELD) 18 | public class Audit { 19 | 20 | @CreatedBy 21 | @Column(name = "CreatedBy") 22 | private Long createdBy; 23 | 24 | @CreatedDate 25 | @Column(name = "CreatedDate") 26 | private Instant createdDate; 27 | 28 | @LastModifiedBy 29 | @Column(name = "UpdatedBy") 30 | private Long lastModifiedBy; 31 | 32 | @LastModifiedDate 33 | @Column(name = "UpdatedDate") 34 | private Instant lastModifiedDate; 35 | 36 | public Audit() { 37 | 38 | } 39 | 40 | public Audit(Long createdBy, Instant createdDate, Long lastModifiedBy, Instant lastModifiedDate) { 41 | this.createdBy = createdBy; 42 | this.createdDate = createdDate; 43 | this.lastModifiedBy = lastModifiedBy; 44 | this.lastModifiedDate = lastModifiedDate; 45 | } 46 | 47 | public Audit(Audit audit) { 48 | this.createdBy = audit.createdBy; 49 | this.createdDate = audit.createdDate; 50 | this.lastModifiedBy = audit.lastModifiedBy; 51 | this.lastModifiedDate = audit.lastModifiedDate; 52 | } 53 | 54 | public Long getCreatedBy() { 55 | return createdBy; 56 | } 57 | 58 | public void setCreatedBy(Long createdBy) { 59 | this.createdBy = createdBy; 60 | } 61 | 62 | public Instant getCreatedDate() { 63 | return createdDate; 64 | } 65 | 66 | public void setCreatedDate(Instant createdDate) { 67 | this.createdDate = createdDate; 68 | } 69 | 70 | public Long getLastModifiedBy() { 71 | return lastModifiedBy; 72 | } 73 | 74 | public void setLastModifiedBy(Long lastModifiedBy) { 75 | this.lastModifiedBy = lastModifiedBy; 76 | } 77 | 78 | public Instant getLastModifiedDate() { 79 | return lastModifiedDate; 80 | } 81 | 82 | public void setLastModifiedDate(Instant lastModifiedDate) { 83 | this.lastModifiedDate = lastModifiedDate; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/jose/KeyGeneratorUtils.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.jose; 2 | 3 | import java.math.BigInteger; 4 | import java.security.KeyPair; 5 | import java.security.KeyPairGenerator; 6 | import java.security.spec.ECFieldFp; 7 | import java.security.spec.ECParameterSpec; 8 | import java.security.spec.ECPoint; 9 | import java.security.spec.EllipticCurve; 10 | 11 | import javax.crypto.KeyGenerator; 12 | import javax.crypto.SecretKey; 13 | 14 | final class KeyGeneratorUtils { 15 | 16 | private KeyGeneratorUtils() { 17 | } 18 | 19 | static SecretKey generateSecretKey() { 20 | SecretKey hmacKey; 21 | try { 22 | hmacKey = KeyGenerator.getInstance("HmacSha256").generateKey(); 23 | } catch (Exception ex) { 24 | throw new IllegalStateException(ex); 25 | } 26 | return hmacKey; 27 | } 28 | 29 | static KeyPair generateRsaKey() { 30 | KeyPair keyPair; 31 | try { 32 | KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); 33 | keyPairGenerator.initialize(2048); 34 | keyPair = keyPairGenerator.generateKeyPair(); 35 | } catch (Exception ex) { 36 | throw new IllegalStateException(ex); 37 | } 38 | return keyPair; 39 | } 40 | 41 | static KeyPair generateEcKey() { 42 | EllipticCurve ellipticCurve = new EllipticCurve( 43 | new ECFieldFp(new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951")), 44 | new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853948"), 45 | new BigInteger("41058363725152142129326129780047268409114441015993725554835256314039467401291")); 46 | 47 | ECPoint ecPoint = new ECPoint(new BigInteger("48439561293906451759052585252797914202762949526041747995844080717082404635286"), 48 | new BigInteger("36134250956749795798585127919587881956611106672985015071877198253568414405109")); 49 | 50 | ECParameterSpec ecParameterSpec = new ECParameterSpec(ellipticCurve, ecPoint, 51 | new BigInteger("115792089210356248762697446949407573529996955224135760342422259061068512044369"), 1); 52 | 53 | KeyPair keyPair; 54 | try { 55 | KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); 56 | keyPairGenerator.initialize(ecParameterSpec); 57 | keyPair = keyPairGenerator.generateKeyPair(); 58 | } catch (Exception ex) { 59 | throw new IllegalStateException(ex); 60 | } 61 | return keyPair; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | There are three projects 2 | 3 | 1) SpringAuthorizationServer 4 | 2) SpringResourceServer 5 | 3) SpringAuthorizationServerClient 6 | 7 | The main classes are OAuth2ResourceOwnerPasswordAuthenticationConverter, OAuth2ResourceOwnerPasswordAuthenticationToken and 8 | OAuth2ResourceOwnerPasswordAuthenticationProvider. These classes are present in SpringAuthorizationServer in package oauth2.authentication. 9 | 10 | In SpringAuthorizationServerClient project. Class WebClientConfig has the configuration for password grant type support (contextAttributesMapper). Changes can be done according to need. 11 | 12 | All are eclipse based gradle projects. All the settings are in application.properties file for all three projects. Like contextpath, port etc. SpringAuthorizationServer is 13 | using H2 database. 14 | 15 | These are the same projects offered by Spring. I just add the Password grant type in the AuthorizationServer and Client as Spring is not providing support 16 | for it becasue of OAuth2.1 draft. 17 | 18 | This project is just showing how you can add custom grant type in the SpringAuthorizationServer. Like in my case I added password grant type support to use in my project. Changes 19 | can be made according to need in the code. Right now it is using version 0.4.2 which is the latest version. Things can be change in upcoming versions of Spring authorization 20 | server. So if you update the version in future and have some problem then ask on the Spring forum. 21 | 22 | This project is just for demonstration purpose to add custom grant type. 23 | 24 | All projects should be imported in eclipse fine. 25 | 26 | 1) By default SpringAuthorizationServer will run on port 9000 with context path /springauthserver 27 | 2) SpringResourceServer will run on port 8090 with context path /springresourceserver 28 | 3) SpringAuthorizationServerClient will run on port 8080 with context path /springauthserverclient 29 | 30 | The database scripts for SpringAuthorizationServer are present in database/scripts folder. The database settings are defined in application.proeprties. 31 | 32 | The Urls are also configure in application.proeprties file 33 | 34 | 1) After running all three projects. Open the url http://127.0.0.1:8080/springauthserverclient (This can be change if you change the properties file) 35 | 2) Already a user1 with password field is populated. Login with the user. 36 | 3) There will be three grant types. Client Credentials, Authorization Code and Password. 37 | 4) Click on password grant type and the result will come. 38 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/customizer/jwt/impl/UsernamePasswordAuthenticationTokenJwtCustomizerHandler.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.customizer.jwt.impl; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Set; 6 | import java.util.stream.Collectors; 7 | 8 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 9 | import org.springframework.security.core.Authentication; 10 | import org.springframework.security.core.GrantedAuthority; 11 | import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; 12 | import org.springframework.security.oauth2.jwt.JwtClaimsSet; 13 | import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; 14 | import org.springframework.util.CollectionUtils; 15 | 16 | import pk.training.basit.jpa.entity.UserPrincipal; 17 | import pk.training.basit.oauth2.customizer.jwt.JwtCustomizerHandler; 18 | 19 | public class UsernamePasswordAuthenticationTokenJwtCustomizerHandler extends AbstractJwtCustomizerHandler { 20 | 21 | public UsernamePasswordAuthenticationTokenJwtCustomizerHandler(JwtCustomizerHandler jwtCustomizerHandler) { 22 | super(jwtCustomizerHandler); 23 | } 24 | 25 | @Override 26 | protected void customizeJwt(JwtEncodingContext jwtEncodingContext) { 27 | 28 | Authentication authentication = jwtEncodingContext.getPrincipal(); 29 | UserPrincipal userPrincipal = (UserPrincipal)authentication.getPrincipal(); 30 | Long userId = userPrincipal.getId(); 31 | Set authorities = userPrincipal.getAuthorities().stream() 32 | .map(GrantedAuthority::getAuthority) 33 | .collect(Collectors.toSet()); 34 | 35 | Map userAttributes = new HashMap<>(); 36 | userAttributes.put("userId", userId); 37 | 38 | Set contextAuthorizedScopes = jwtEncodingContext.getAuthorizedScopes(); 39 | 40 | JwtClaimsSet.Builder jwtClaimSetBuilder = jwtEncodingContext.getClaims(); 41 | 42 | if (CollectionUtils.isEmpty(contextAuthorizedScopes)) { 43 | jwtClaimSetBuilder.claim(OAuth2ParameterNames.SCOPE, authorities); 44 | } 45 | 46 | jwtClaimSetBuilder.claims(claims -> 47 | userAttributes.entrySet().stream() 48 | .forEach(entry -> claims.put(entry.getKey(), entry.getValue())) 49 | ); 50 | 51 | } 52 | 53 | @Override 54 | protected boolean supportCustomizeContext(Authentication authentication) { 55 | return authentication != null && authentication instanceof UsernamePasswordAuthenticationToken; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 | 20 | 21 |
22 | 25 |
26 | 27 |
28 | 29 |
30 |
31 | 32 |
33 | 34 |
35 | 36 |
37 | 38 |
39 | 40 |
41 | 42 | 52 |
53 |
54 |
55 | 56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/federated/identity/FederatedIdentityIdTokenCustomizer.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.federated.identity; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | import org.springframework.security.core.Authentication; 11 | import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; 12 | import org.springframework.security.oauth2.core.oidc.OidcIdToken; 13 | import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames; 14 | import org.springframework.security.oauth2.core.oidc.user.OidcUser; 15 | import org.springframework.security.oauth2.core.user.OAuth2User; 16 | import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; 17 | import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer; 18 | 19 | public final class FederatedIdentityIdTokenCustomizer implements OAuth2TokenCustomizer { 20 | 21 | private static final Set ID_TOKEN_CLAIMS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( 22 | IdTokenClaimNames.ISS, 23 | IdTokenClaimNames.SUB, 24 | IdTokenClaimNames.AUD, 25 | IdTokenClaimNames.EXP, 26 | IdTokenClaimNames.IAT, 27 | IdTokenClaimNames.AUTH_TIME, 28 | IdTokenClaimNames.NONCE, 29 | IdTokenClaimNames.ACR, 30 | IdTokenClaimNames.AMR, 31 | IdTokenClaimNames.AZP, 32 | IdTokenClaimNames.AT_HASH, 33 | IdTokenClaimNames.C_HASH 34 | ))); 35 | 36 | @Override 37 | public void customize(JwtEncodingContext context) { 38 | if (OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue())) { 39 | Map thirdPartyClaims = extractClaims(context.getPrincipal()); 40 | context.getClaims().claims(existingClaims -> { 41 | 42 | // Remove conflicting claims set by this authorization server 43 | existingClaims.keySet().forEach(thirdPartyClaims::remove); 44 | 45 | // Remove standard id_token claims that could cause problems with clients 46 | ID_TOKEN_CLAIMS.forEach(thirdPartyClaims::remove); 47 | 48 | // Add all other claims directly to id_token 49 | existingClaims.putAll(thirdPartyClaims); 50 | }); 51 | } 52 | } 53 | 54 | private Map extractClaims(Authentication principal) { 55 | Map claims; 56 | if (principal.getPrincipal() instanceof OidcUser) { 57 | OidcUser oidcUser = (OidcUser) principal.getPrincipal(); 58 | OidcIdToken idToken = oidcUser.getIdToken(); 59 | claims = idToken.getClaims(); 60 | } else if (principal.getPrincipal() instanceof OAuth2User) { 61 | OAuth2User oauth2User = (OAuth2User) principal.getPrincipal(); 62 | claims = oauth2User.getAttributes(); 63 | } else { 64 | claims = Collections.emptyMap(); 65 | } 66 | 67 | return new HashMap<>(claims); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/federated/identity/FederatedIdentityAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.federated.identity; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | import org.springframework.http.server.ServletServerHttpRequest; 10 | import org.springframework.security.core.AuthenticationException; 11 | import org.springframework.security.oauth2.client.registration.ClientRegistration; 12 | import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; 13 | import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter; 14 | import org.springframework.security.web.AuthenticationEntryPoint; 15 | import org.springframework.security.web.DefaultRedirectStrategy; 16 | import org.springframework.security.web.RedirectStrategy; 17 | import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; 18 | import org.springframework.web.util.UriComponentsBuilder; 19 | 20 | public final class FederatedIdentityAuthenticationEntryPoint implements AuthenticationEntryPoint { 21 | 22 | private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); 23 | 24 | private String authorizationRequestUri = OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI 25 | + "/{registrationId}"; 26 | 27 | private final AuthenticationEntryPoint delegate; 28 | 29 | private final ClientRegistrationRepository clientRegistrationRepository; 30 | 31 | public FederatedIdentityAuthenticationEntryPoint(String loginPageUrl, ClientRegistrationRepository clientRegistrationRepository) { 32 | this.delegate = new LoginUrlAuthenticationEntryPoint(loginPageUrl); 33 | this.clientRegistrationRepository = clientRegistrationRepository; 34 | } 35 | 36 | @Override 37 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException { 38 | String idp = request.getParameter("idp"); 39 | if (idp != null) { 40 | ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(idp); 41 | if (clientRegistration != null) { 42 | String redirectUri = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request)) 43 | .replaceQuery(null).replacePath(this.authorizationRequestUri) 44 | .buildAndExpand(clientRegistration.getRegistrationId()).toUriString(); 45 | this.redirectStrategy.sendRedirect(request, response, redirectUri); 46 | return; 47 | } 48 | } 49 | 50 | this.delegate.commence(request, response, authenticationException); 51 | } 52 | 53 | public void setAuthorizationRequestUri(String authorizationRequestUri) { 54 | this.authorizationRequestUri = authorizationRequestUri; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/registered/client/impl/ClientCredentialsOAuth2RegisteredClient.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.registered.client.impl; 2 | 3 | import java.util.Set; 4 | import java.util.stream.Collectors; 5 | import java.util.stream.Stream; 6 | 7 | import org.apache.logging.log4j.LogManager; 8 | import org.apache.logging.log4j.Logger; 9 | import org.springframework.core.env.Environment; 10 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 11 | import org.springframework.security.oauth2.core.ClientAuthenticationMethod; 12 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; 13 | import org.springframework.stereotype.Component; 14 | 15 | import pk.training.basit.configuration.token.OAuth2TokenSettings; 16 | 17 | @Component 18 | public class ClientCredentialsOAuth2RegisteredClient extends AbstractOAuth2RegisteredClient { 19 | 20 | private static final Logger LOGGER = LogManager.getLogger(ClientCredentialsOAuth2RegisteredClient.class); 21 | 22 | private static final String CLIENT_CREDENTIALS_CLIENT = "client.credentials"; 23 | 24 | public ClientCredentialsOAuth2RegisteredClient(Environment env, OAuth2TokenSettings oauth2TokenSettings) { 25 | super(env, oauth2TokenSettings); 26 | LOGGER.debug("In ClientCredentialsOAuth2RegisteredClient"); 27 | } 28 | 29 | @Override 30 | public RegisteredClient getRegisteredClient() { 31 | 32 | LOGGER.debug("In ClientCredentialsOAuth2RegisteredClient.getRegisteredClient()"); 33 | 34 | String authorizationCodeClientScope = getClientProperty(CLIENT_CREDENTIALS_CLIENT, SCOPE); 35 | 36 | Set scopeSet = Stream.of(authorizationCodeClientScope.split(",", -1)).collect(Collectors.toSet()); 37 | 38 | RegisteredClient.Builder registeredClientBuilder = getRegisteredClientBuilder(); 39 | RegisteredClient clientCredentialsRegisteredClient = registeredClientBuilder.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) 40 | .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) 41 | .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) 42 | .scopes(scopes -> scopes.addAll(scopeSet)) 43 | .build(); 44 | 45 | return clientCredentialsRegisteredClient; 46 | 47 | } 48 | 49 | @Override 50 | public String getId() { 51 | return "1"; 52 | } 53 | 54 | @Override 55 | public String getClientId() { 56 | String clientCredentialsClientId = getClientProperty(CLIENT_CREDENTIALS_CLIENT, ID); 57 | return clientCredentialsClientId; 58 | } 59 | 60 | @Override 61 | public String getClientName() { 62 | String clientCredentialsClientName = getClientProperty(CLIENT_CREDENTIALS_CLIENT, NAME); 63 | return clientCredentialsClientName; 64 | } 65 | 66 | @Override 67 | public String getClientSecret() { 68 | String clientCredentialsClientSecret = getClientProperty(CLIENT_CREDENTIALS_CLIENT, SECRET); 69 | return clientCredentialsClientSecret; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/authentication/OAuth2ResourceOwnerPasswordAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.authentication; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.HashSet; 6 | import java.util.Map; 7 | import java.util.Set; 8 | 9 | import org.springframework.lang.Nullable; 10 | import org.springframework.security.authentication.AbstractAuthenticationToken; 11 | import org.springframework.security.core.Authentication; 12 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 13 | import org.springframework.util.Assert; 14 | 15 | public class OAuth2ResourceOwnerPasswordAuthenticationToken extends AbstractAuthenticationToken { 16 | 17 | private static final long serialVersionUID = -6067207202119450764L; 18 | 19 | private final AuthorizationGrantType authorizationGrantType; 20 | private final Authentication clientPrincipal; 21 | private final Set scopes; 22 | private final Map additionalParameters; 23 | 24 | /** 25 | * Constructs an {@code OAuth2ClientCredentialsAuthenticationToken} using the provided parameters. 26 | * 27 | * @param clientPrincipal the authenticated client principal 28 | */ 29 | 30 | public OAuth2ResourceOwnerPasswordAuthenticationToken(AuthorizationGrantType authorizationGrantType, 31 | Authentication clientPrincipal, @Nullable Set scopes, @Nullable Map additionalParameters) { 32 | super(Collections.emptyList()); 33 | Assert.notNull(authorizationGrantType, "authorizationGrantType cannot be null"); 34 | Assert.notNull(clientPrincipal, "clientPrincipal cannot be null"); 35 | this.authorizationGrantType = authorizationGrantType; 36 | this.clientPrincipal = clientPrincipal; 37 | this.scopes = Collections.unmodifiableSet(scopes != null ? new HashSet<>(scopes) : Collections.emptySet()); 38 | this.additionalParameters = Collections.unmodifiableMap(additionalParameters != null ? new HashMap<>(additionalParameters) : Collections.emptyMap()); 39 | } 40 | 41 | /** 42 | * Returns the authorization grant type. 43 | * 44 | * @return the authorization grant type 45 | */ 46 | public AuthorizationGrantType getGrantType() { 47 | return this.authorizationGrantType; 48 | } 49 | 50 | @Override 51 | public Object getPrincipal() { 52 | return this.clientPrincipal; 53 | } 54 | 55 | @Override 56 | public Object getCredentials() { 57 | return ""; 58 | } 59 | 60 | /** 61 | * Returns the requested scope(s). 62 | * 63 | * @return the requested scope(s), or an empty {@code Set} if not available 64 | */ 65 | public Set getScopes() { 66 | return this.scopes; 67 | } 68 | 69 | /** 70 | * Returns the additional parameters. 71 | * 72 | * @return the additional parameters 73 | */ 74 | public Map getAdditionalParameters() { 75 | return this.additionalParameters; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/token/impl/OAuth2TokenSettingsImpl.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.token.impl; 2 | 3 | import java.time.Duration; 4 | import java.time.temporal.ChronoUnit; 5 | 6 | import org.apache.logging.log4j.LogManager; 7 | import org.apache.logging.log4j.Logger; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.security.oauth2.server.authorization.settings.TokenSettings; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.util.StringUtils; 12 | 13 | import pk.training.basit.configuration.token.OAuth2TokenSettings; 14 | 15 | @Component 16 | public class OAuth2TokenSettingsImpl implements OAuth2TokenSettings { 17 | 18 | private static final Logger LOGGER = LogManager.getLogger(OAuth2TokenSettingsImpl.class); 19 | 20 | private final long accessTokenTime; 21 | private final String accessTokenTimeUnit; 22 | private final long refreshTokenTime; 23 | private final String refreshTokenTimeUnit; 24 | 25 | public OAuth2TokenSettingsImpl(@Value("${oauth2.access.token.time}") long accessTokenTime, 26 | @Value("${oauth2.access.token.time.unit}") String accessTokenTimeUnit, 27 | @Value("${oauth2.refresh.token.time}") long refreshTokenTime, 28 | @Value("${oauth2.refresh.token.time.unit}") String refreshTokenTimeUnit) { 29 | 30 | LOGGER.debug("in OAuth2TokenSettingImpl"); 31 | 32 | this.accessTokenTime = accessTokenTime; 33 | this.accessTokenTimeUnit = accessTokenTimeUnit; 34 | this.refreshTokenTime = refreshTokenTime; 35 | this.refreshTokenTimeUnit = refreshTokenTimeUnit; 36 | } 37 | 38 | @Override 39 | public TokenSettings getTokenSettings() { 40 | 41 | Duration accessTokenDuration = setTokenTime(accessTokenTimeUnit, accessTokenTime, 5); 42 | Duration refreshTokenDuration = setTokenTime(refreshTokenTimeUnit, refreshTokenTime, 60); 43 | 44 | TokenSettings.Builder tokenSettingsBuilder = TokenSettings.builder().accessTokenTimeToLive(accessTokenDuration) 45 | .refreshTokenTimeToLive(refreshTokenDuration); 46 | TokenSettings tokenSetting = tokenSettingsBuilder.build(); 47 | return tokenSetting; 48 | 49 | } 50 | 51 | private Duration setTokenTime(String tokenTimeUnit, long tokenTime, long durationInMinutes) { 52 | 53 | Duration duration = Duration.ofMinutes(durationInMinutes); 54 | 55 | if (StringUtils.hasText(tokenTimeUnit)) { 56 | 57 | switch (tokenTimeUnit.toUpperCase()) { 58 | case "M": 59 | case "MINUTE": 60 | case "MINUTES": 61 | duration = Duration.ofMinutes(tokenTime); 62 | break; 63 | case "H": 64 | case "HOUR": 65 | case "HOURS": 66 | duration = Duration.ofHours(tokenTime); 67 | break; 68 | case "D": 69 | case "DAY": 70 | case "DAYS": 71 | duration = Duration.ofDays(tokenTime); 72 | break; 73 | case "W": 74 | case "WEEK": 75 | case "WEEKS": 76 | duration = Duration.of(tokenTime, ChronoUnit.WEEKS); 77 | break; 78 | } 79 | } 80 | 81 | return duration; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /SpringResourceServer/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/database/scripts/schema-oauth2-sql-server.sql: -------------------------------------------------------------------------------- 1 | IF NOT EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME = 'oauth2_registered_client' AND XTYPE='U') 2 | BEGIN TRY 3 | -- SCHEMA 4 | CREATE TABLE oauth2_registered_client ( 5 | id varchar(100) NOT NULL, 6 | client_id VARCHAR(100) NOT NULL, 7 | client_id_issued_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, 8 | client_secret VARCHAR(200) DEFAULT NULL, 9 | client_secret_expires_at DATETIME DEFAULT NULL, 10 | client_name VARCHAR(200) NOT NULL, 11 | client_authentication_methods VARCHAR(1000) NOT NULL, 12 | authorization_grant_types VARCHAR(1000) NOT NULL, 13 | redirect_uris VARCHAR(1000) DEFAULT NULL, 14 | scopes VARCHAR(1000) NOT NULL, 15 | client_settings VARCHAR(2000) NOT NULL, 16 | token_settings VARCHAR(2000) NOT NULL, 17 | PRIMARY KEY (id) 18 | ); 19 | END TRY 20 | BEGIN CATCH 21 | SELECT ERROR_MESSAGE() AS 'oauth2_registered_client Message' 22 | END CATCH 23 | 24 | IF NOT EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME = 'oauth2_authorization' AND XTYPE='U') 25 | BEGIN TRY 26 | -- SCHEMA 27 | CREATE TABLE oauth2_authorization ( 28 | id VARCHAR(100) NOT NULL, 29 | registered_client_id VARCHAR(100) NOT NULL, 30 | principal_name VARCHAR(200) NOT NULL, 31 | authorization_grant_type VARCHAR(100) NOT NULL, 32 | attributes VARCHAR(4000) DEFAULT NULL, 33 | state VARCHAR(500) DEFAULT NULL, 34 | authorization_code_value VARBINARY(MAX) DEFAULT NULL, 35 | authorization_code_issued_at DATETIME DEFAULT NULL, 36 | authorization_code_expires_at DATETIME DEFAULT NULL, 37 | authorization_code_metadata VARCHAR(2000) DEFAULT NULL, 38 | access_token_value VARBINARY(MAX) DEFAULT NULL, 39 | access_token_issued_at DATETIME DEFAULT NULL, 40 | access_token_expires_at DATETIME DEFAULT NULL, 41 | access_token_metadata VARCHAR(2000) DEFAULT NULL, 42 | access_token_type VARCHAR(100) DEFAULT NULL, 43 | access_token_scopes VARCHAR(1000) DEFAULT NULL, 44 | oidc_id_token_value VARBINARY(MAX) DEFAULT NULL, 45 | oidc_id_token_issued_at DATETIME DEFAULT NULL, 46 | oidc_id_token_expires_at DATETIME DEFAULT NULL, 47 | oidc_id_token_metadata VARCHAR(2000) DEFAULT NULL, 48 | refresh_token_value VARBINARY(MAX) DEFAULT NULL, 49 | refresh_token_issued_at DATETIME DEFAULT NULL, 50 | refresh_token_expires_at DATETIME DEFAULT NULL, 51 | refresh_token_metadata VARCHAR(2000) DEFAULT NULL, 52 | PRIMARY KEY (id) 53 | ); 54 | END TRY 55 | BEGIN CATCH 56 | SELECT ERROR_MESSAGE() AS 'oauth2_authorization Message' 57 | END CATCH 58 | 59 | IF NOT EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME = 'oauth2_authorization_consent' AND XTYPE='U') 60 | BEGIN TRY 61 | -- SCHEMA 62 | CREATE TABLE oauth2_authorization_consent ( 63 | registered_client_id VARCHAR(100) NOT NULL, 64 | principal_name VARCHAR(200) NOT NULL, 65 | authorities VARCHAR(1000) NOT NULL, 66 | PRIMARY KEY (registered_client_id, principal_name) 67 | ); 68 | END TRY 69 | BEGIN CATCH 70 | SELECT ERROR_MESSAGE() AS 'oauth2_authorization_consent Message' 71 | END CATCH 72 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/registered/client/impl/AuthorizationCodeOAuth2RegisteredClient.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.registered.client.impl; 2 | 3 | import java.util.Set; 4 | import java.util.stream.Collectors; 5 | import java.util.stream.Stream; 6 | 7 | import org.apache.logging.log4j.LogManager; 8 | import org.apache.logging.log4j.Logger; 9 | import org.springframework.core.env.Environment; 10 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 11 | import org.springframework.security.oauth2.core.ClientAuthenticationMethod; 12 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; 13 | import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; 14 | import org.springframework.stereotype.Component; 15 | 16 | import pk.training.basit.configuration.token.OAuth2TokenSettings; 17 | 18 | @Component 19 | public class AuthorizationCodeOAuth2RegisteredClient extends AbstractOAuth2RegisteredClient { 20 | 21 | private static final Logger LOGGER = LogManager.getLogger(AuthorizationCodeOAuth2RegisteredClient.class); 22 | 23 | private static final String AUTHORIZATION_CODE_CLIENT = "authorization.code"; 24 | 25 | public AuthorizationCodeOAuth2RegisteredClient(Environment env, OAuth2TokenSettings oauth2TokenSettings) { 26 | super(env, oauth2TokenSettings); 27 | LOGGER.debug("In AuthorizationCodeOAuth2RegisteredClient"); 28 | } 29 | 30 | @Override 31 | public RegisteredClient getRegisteredClient() { 32 | 33 | LOGGER.debug("In AuthorizationCodeOAuth2RegisteredClient.getRegisteredClient()"); 34 | 35 | String authorizationCodeClientRedirectUri = getClientProperty(AUTHORIZATION_CODE_CLIENT, REDIRECT_URI); 36 | String authorizationCodeClientScope = getClientProperty(AUTHORIZATION_CODE_CLIENT, SCOPE); 37 | 38 | Set scopeSet = Stream.of(authorizationCodeClientScope.split(",", -1)).collect(Collectors.toSet()); 39 | ClientSettings clientSettings = ClientSettings.builder().requireAuthorizationConsent(true).build(); 40 | 41 | RegisteredClient.Builder registeredClientBuilder = getRegisteredClientBuilder(); 42 | RegisteredClient authorizationCodeRegisteredClient = registeredClientBuilder.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST) 43 | .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) 44 | .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) 45 | .redirectUri(authorizationCodeClientRedirectUri) 46 | .scopes(scopes -> scopes.addAll(scopeSet)) 47 | .clientSettings(clientSettings) 48 | .build(); 49 | 50 | return authorizationCodeRegisteredClient; 51 | 52 | } 53 | 54 | @Override 55 | public String getId() { 56 | return "2"; 57 | } 58 | 59 | @Override 60 | public String getClientId() { 61 | String authorizationCodeClientId = getClientProperty(AUTHORIZATION_CODE_CLIENT, ID); 62 | return authorizationCodeClientId; 63 | } 64 | 65 | @Override 66 | public String getClientName() { 67 | String authorizationCodeClientName = getClientProperty(AUTHORIZATION_CODE_CLIENT, NAME); 68 | return authorizationCodeClientName; 69 | } 70 | 71 | @Override 72 | public String getClientSecret() { 73 | String authorizationCodeClientSecret = getClientProperty(AUTHORIZATION_CODE_CLIENT, SECRET); 74 | return authorizationCodeClientSecret; 75 | } 76 | 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/customizer/jwt/impl/OAuth2AuthenticationTokenJwtCustomizerHandler.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.customizer.jwt.impl; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | import org.springframework.security.core.Authentication; 11 | import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; 12 | import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; 13 | import org.springframework.security.oauth2.core.oidc.OidcIdToken; 14 | import org.springframework.security.oauth2.core.oidc.user.OidcUser; 15 | import org.springframework.security.oauth2.core.user.OAuth2User; 16 | import org.springframework.security.oauth2.jwt.JwtClaimsSet; 17 | import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; 18 | 19 | import pk.training.basit.oauth2.customizer.jwt.JwtCustomizerHandler; 20 | 21 | public class OAuth2AuthenticationTokenJwtCustomizerHandler extends AbstractJwtCustomizerHandler { 22 | 23 | private final Set ID_TOKEN_CLAIMS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( 24 | IdTokenClaimNames.ISS, 25 | IdTokenClaimNames.SUB, 26 | IdTokenClaimNames.AUD, 27 | IdTokenClaimNames.EXP, 28 | IdTokenClaimNames.IAT, 29 | IdTokenClaimNames.AUTH_TIME, 30 | IdTokenClaimNames.NONCE, 31 | IdTokenClaimNames.ACR, 32 | IdTokenClaimNames.AMR, 33 | IdTokenClaimNames.AZP, 34 | IdTokenClaimNames.AT_HASH, 35 | IdTokenClaimNames.C_HASH 36 | ))); 37 | 38 | public OAuth2AuthenticationTokenJwtCustomizerHandler(JwtCustomizerHandler jwtCustomizerHandler) { 39 | super(jwtCustomizerHandler); 40 | } 41 | 42 | @Override 43 | protected void customizeJwt(JwtEncodingContext jwtEncodingContext) { 44 | 45 | Authentication authentication = jwtEncodingContext.getPrincipal(); 46 | 47 | Map thirdPartyClaims = extractClaims(authentication); 48 | 49 | JwtClaimsSet.Builder jwtClaimSetBuilder = jwtEncodingContext.getClaims(); 50 | 51 | jwtClaimSetBuilder.claims(existingClaims -> { 52 | 53 | // Remove conflicting claims set by this authorization server 54 | existingClaims.keySet().forEach(thirdPartyClaims::remove); 55 | 56 | // Remove standard id_token claims that could cause problems with clients 57 | ID_TOKEN_CLAIMS.forEach(thirdPartyClaims::remove); 58 | 59 | // Add all other claims directly to id_token 60 | existingClaims.putAll(thirdPartyClaims); 61 | }); 62 | 63 | } 64 | 65 | private Map extractClaims(Authentication authentication) { 66 | Map claims; 67 | Object principalObj = authentication.getPrincipal(); 68 | if (principalObj instanceof OidcUser) { 69 | OidcUser oidcUser = (OidcUser) principalObj; 70 | OidcIdToken idToken = oidcUser.getIdToken(); 71 | claims = idToken.getClaims(); 72 | } else if (principalObj instanceof OAuth2User) { 73 | OAuth2User oauth2User = (OAuth2User) principalObj; 74 | claims = oauth2User.getAttributes(); 75 | } else { 76 | claims = Collections.emptyMap(); 77 | } 78 | 79 | return new HashMap<>(claims); 80 | } 81 | 82 | @Override 83 | protected boolean supportCustomizeContext(Authentication authentication) { 84 | return authentication != null && authentication instanceof OAuth2AuthenticationToken; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Spring Security OAuth 2.0 Sample 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 20 |
21 |
22 | 26 |
27 |
28 |

Authorize the client using grant_type:

29 |
30 | 41 | 51 |
52 |
53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/SecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration; 2 | 3 | import org.apache.logging.log4j.LogManager; 4 | import org.apache.logging.log4j.Logger; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; 7 | import org.springframework.boot.autoconfigure.security.servlet.PathRequest; 8 | import org.springframework.context.annotation.AdviceMode; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 11 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 12 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 13 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 14 | import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; 15 | import org.springframework.security.web.SecurityFilterChain; 16 | 17 | import pk.training.basit.configuration.federated.identity.FederatedIdentityConfigurer; 18 | import pk.training.basit.configuration.federated.identity.UserRepositoryOAuth2UserHandler; 19 | import pk.training.basit.service.UserPrincipalService; 20 | 21 | @EnableGlobalMethodSecurity( 22 | prePostEnabled = true, 23 | order = 0, 24 | mode = AdviceMode.PROXY, 25 | proxyTargetClass = false 26 | ) 27 | @EnableWebSecurity 28 | public class SecurityConfiguration { 29 | 30 | private static final Logger LOGGER = LogManager.getLogger(SecurityConfiguration.class); 31 | 32 | @Autowired 33 | private UserPrincipalService userPrincipalService; 34 | 35 | // If no passwordEncoder bean is defined then you have to prefix password like {noop}secret1, or {bcrypt}password 36 | // if not static spring boot 2.6.x gives bean currently in creation error at line .passwordEncoder(passwordEncoder()) in configureGlobal() method 37 | /** 38 | @Bean 39 | public static PasswordEncoder passwordEncoder() { 40 | LOGGER.debug("in passwordEncoder"); 41 | return new BCryptPasswordEncoder(); 42 | }; 43 | */ 44 | 45 | @Autowired 46 | protected void configureGlobal(AuthenticationManagerBuilder builder) throws Exception { 47 | LOGGER.debug("in configureGlobal"); 48 | builder 49 | .userDetailsService(this.userPrincipalService) 50 | // .passwordEncoder(passwordEncoder()) 51 | .and() 52 | .eraseCredentials(true); 53 | } 54 | 55 | @Bean 56 | public WebSecurityCustomizer webSecurityCustomizer() { 57 | return (web) -> web.ignoring().antMatchers("/webjars/**", "/image/**"); 58 | } 59 | 60 | @Bean 61 | public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { 62 | LOGGER.debug("in configure HttpSecurity"); 63 | 64 | FederatedIdentityConfigurer federatedIdentityConfigurer = new FederatedIdentityConfigurer().oauth2UserHandler(new UserRepositoryOAuth2UserHandler()); 65 | 66 | http.authorizeRequests(authorizeRequests -> authorizeRequests.requestMatchers(EndpointRequest.toAnyEndpoint(),PathRequest.toH2Console()).permitAll() 67 | .anyRequest().authenticated() 68 | ) 69 | .formLogin(form -> form.loginPage("/login").failureUrl("/login-error").permitAll()) 70 | .csrf().ignoringRequestMatchers(PathRequest.toH2Console()) 71 | .and().headers().frameOptions().sameOrigin() 72 | .and() 73 | .apply(federatedIdentityConfigurer); 74 | 75 | return http.build(); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/authentication/OAuth2ResourceOwnerPasswordAuthenticationConverter.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.oauth2.authentication; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashSet; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import java.util.stream.Collectors; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | 11 | import org.springframework.security.core.Authentication; 12 | import org.springframework.security.core.context.SecurityContextHolder; 13 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 14 | import org.springframework.security.oauth2.core.OAuth2ErrorCodes; 15 | import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; 16 | import org.springframework.security.web.authentication.AuthenticationConverter; 17 | import org.springframework.util.MultiValueMap; 18 | import org.springframework.util.StringUtils; 19 | 20 | public class OAuth2ResourceOwnerPasswordAuthenticationConverter implements AuthenticationConverter { 21 | 22 | @Override 23 | public Authentication convert(HttpServletRequest request) { 24 | 25 | // grant_type (REQUIRED) 26 | String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE); 27 | if (!AuthorizationGrantType.PASSWORD.getValue().equals(grantType)) { 28 | return null; 29 | } 30 | 31 | MultiValueMap parameters = OAuth2EndpointUtils.getParameters(request); 32 | 33 | // scope (OPTIONAL) 34 | String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE); 35 | if (StringUtils.hasText(scope) && 36 | parameters.get(OAuth2ParameterNames.SCOPE).size() != 1) { 37 | OAuth2EndpointUtils.throwError( 38 | OAuth2ErrorCodes.INVALID_REQUEST, 39 | OAuth2ParameterNames.SCOPE, 40 | OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); 41 | } 42 | 43 | Set requestedScopes = null; 44 | if (StringUtils.hasText(scope)) { 45 | requestedScopes = new HashSet<>( 46 | Arrays.asList(StringUtils.delimitedListToStringArray(scope, " "))); 47 | } 48 | 49 | // username (REQUIRED) 50 | String username = parameters.getFirst(OAuth2ParameterNames.USERNAME); 51 | if (!StringUtils.hasText(username) || parameters.get(OAuth2ParameterNames.USERNAME).size() != 1) { 52 | OAuth2EndpointUtils.throwError( 53 | OAuth2ErrorCodes.INVALID_REQUEST, 54 | OAuth2ParameterNames.USERNAME, 55 | OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); 56 | } 57 | 58 | // password (REQUIRED) 59 | String password = parameters.getFirst(OAuth2ParameterNames.PASSWORD); 60 | if (!StringUtils.hasText(password) || parameters.get(OAuth2ParameterNames.PASSWORD).size() != 1) { 61 | OAuth2EndpointUtils.throwError( 62 | OAuth2ErrorCodes.INVALID_REQUEST, 63 | OAuth2ParameterNames.PASSWORD, 64 | OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); 65 | } 66 | 67 | Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication(); 68 | if (clientPrincipal == null) { 69 | OAuth2EndpointUtils.throwError( 70 | OAuth2ErrorCodes.INVALID_REQUEST, 71 | OAuth2ErrorCodes.INVALID_CLIENT, 72 | OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); 73 | } 74 | 75 | Map additionalParameters = parameters 76 | .entrySet() 77 | .stream() 78 | .filter(e -> !e.getKey().equals(OAuth2ParameterNames.GRANT_TYPE) && 79 | !e.getKey().equals(OAuth2ParameterNames.SCOPE)) 80 | .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0))); 81 | 82 | return new OAuth2ResourceOwnerPasswordAuthenticationToken(AuthorizationGrantType.PASSWORD, clientPrincipal, requestedScopes, additionalParameters); 83 | 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/controller/web/AuthorizationController.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.controller.web; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId; 6 | import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient; 7 | 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; 10 | import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; 11 | import org.springframework.security.oauth2.core.OAuth2Error; 12 | import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; 13 | import org.springframework.stereotype.Controller; 14 | import org.springframework.ui.Model; 15 | import org.springframework.util.StringUtils; 16 | import org.springframework.web.bind.annotation.GetMapping; 17 | import org.springframework.web.reactive.function.client.WebClient; 18 | 19 | @Controller 20 | public class AuthorizationController { 21 | 22 | private final WebClient webClient; 23 | private final String messagesBaseUri; 24 | 25 | public AuthorizationController(WebClient webClient, @Value("${messages.base-uri}") String messagesBaseUri) { 26 | this.webClient = webClient; 27 | this.messagesBaseUri = messagesBaseUri; 28 | } 29 | 30 | @GetMapping(value = "/authorize", params = "grant_type=authorization_code") 31 | public String authorizationCodeGrant(Model model, @RegisteredOAuth2AuthorizedClient("authorization-code-client-name") 32 | OAuth2AuthorizedClient authorizedClient) { 33 | 34 | String[] messages = this.webClient 35 | .get() 36 | .uri(this.messagesBaseUri) 37 | .attributes(oauth2AuthorizedClient(authorizedClient)) 38 | .retrieve() 39 | .bodyToMono(String[].class) 40 | .block(); 41 | 42 | model.addAttribute("messages", messages); 43 | 44 | return "index"; 45 | } 46 | 47 | // '/authorized' is the registered 'redirect_uri' for authorization_code 48 | @GetMapping(value = "/authorized", params = OAuth2ParameterNames.ERROR) 49 | public String authorizationFailed(Model model, HttpServletRequest request) { 50 | 51 | String errorCode = request.getParameter(OAuth2ParameterNames.ERROR); 52 | 53 | if (StringUtils.hasText(errorCode)) { 54 | String errorDescription = request.getParameter(OAuth2ParameterNames.ERROR_DESCRIPTION); 55 | String errorUri = request.getParameter(OAuth2ParameterNames.ERROR_URI); 56 | model.addAttribute("error", new OAuth2Error(errorCode, errorDescription, errorUri)); 57 | } 58 | 59 | return "index"; 60 | } 61 | 62 | @GetMapping(value = "/authorize", params = "grant_type=client_credentials") 63 | public String clientCredentialsGrant(Model model) { 64 | 65 | String[] messages = this.webClient 66 | .get() 67 | .uri(this.messagesBaseUri) 68 | .attributes(clientRegistrationId("client-credentials-client-name")) 69 | .retrieve() 70 | .bodyToMono(String[].class) 71 | .block(); 72 | 73 | model.addAttribute("messages", messages); 74 | 75 | return "index"; 76 | } 77 | 78 | @GetMapping(value = "/authorize", params = "grant_type=password") 79 | public String passwordGrant(Model model) { 80 | 81 | String[] messages = this.webClient 82 | .get() 83 | .uri(this.messagesBaseUri) 84 | .attributes(clientRegistrationId("password-client-name")) 85 | .retrieve() 86 | .bodyToMono(String[].class) 87 | .block(); 88 | 89 | model.addAttribute("messages", messages); 90 | 91 | return "index"; 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jackson2/deserializer/UserPrincipalDeserializer.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.jackson2.deserializer; 2 | 3 | import java.io.IOException; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | 7 | import com.fasterxml.jackson.core.JsonParseException; 8 | import com.fasterxml.jackson.core.JsonParser; 9 | import com.fasterxml.jackson.core.JsonProcessingException; 10 | import com.fasterxml.jackson.core.type.TypeReference; 11 | import com.fasterxml.jackson.databind.DeserializationContext; 12 | import com.fasterxml.jackson.databind.JsonDeserializer; 13 | import com.fasterxml.jackson.databind.JsonMappingException; 14 | import com.fasterxml.jackson.databind.JsonNode; 15 | import com.fasterxml.jackson.databind.ObjectMapper; 16 | import com.fasterxml.jackson.databind.node.ArrayNode; 17 | import com.fasterxml.jackson.databind.node.MissingNode; 18 | 19 | import pk.training.basit.jpa.audit.AuditDeletedDate; 20 | import pk.training.basit.jpa.entity.UserAuthority; 21 | import pk.training.basit.jpa.entity.UserPrincipal; 22 | 23 | public class UserPrincipalDeserializer extends JsonDeserializer { 24 | 25 | private static final TypeReference AUDIT_DELETED_DATE_OBJECT = new TypeReference() {}; 26 | 27 | @Override 28 | public UserPrincipal deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 29 | 30 | ObjectMapper mapper = (ObjectMapper) jp.getCodec(); 31 | JsonNode jsonNode = mapper.readTree(jp); 32 | final JsonNode authoritiesNode = readJsonNode(jsonNode, "authorities"); 33 | Set userAuthorities = getUserAuthorities(mapper, authoritiesNode); 34 | 35 | Long id = readJsonNode(jsonNode, "id").asLong(); 36 | String username = readJsonNode(jsonNode, "username").asText(); 37 | JsonNode passwordNode = readJsonNode(jsonNode, "password"); 38 | String password = passwordNode.asText(""); 39 | boolean enabled = readJsonNode(jsonNode, "enabled").asBoolean(); 40 | boolean accountNonExpired = readJsonNode(jsonNode, "accountNonExpired").asBoolean(); 41 | boolean credentialsNonExpired = readJsonNode(jsonNode, "credentialsNonExpired").asBoolean(); 42 | boolean accountNonLocked = readJsonNode(jsonNode, "accountNonLocked").asBoolean(); 43 | final JsonNode auditNode = readJsonNode(jsonNode, "audit"); 44 | 45 | AuditDeletedDate auditDeletedDate = null; 46 | if (!auditNode.isNull() || !auditNode.isMissingNode()) { 47 | auditDeletedDate = mapper.readValue(auditNode.toString(), AUDIT_DELETED_DATE_OBJECT); 48 | } 49 | 50 | UserPrincipal userPrincipal = new UserPrincipal(id, username, password, enabled, accountNonExpired, credentialsNonExpired, 51 | accountNonLocked, userAuthorities, auditDeletedDate); 52 | if (passwordNode.asText(null) == null) { 53 | userPrincipal.eraseCredentials(); 54 | } 55 | 56 | return userPrincipal; 57 | 58 | } 59 | 60 | private JsonNode readJsonNode(JsonNode jsonNode, String field) { 61 | return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance(); 62 | } 63 | 64 | private Set getUserAuthorities(final ObjectMapper mapper, final JsonNode authoritiesNode) throws JsonParseException, JsonMappingException, IOException { 65 | 66 | Set userAuthorities = new HashSet<>(); 67 | if (authoritiesNode != null) { 68 | if (authoritiesNode.isArray()) { 69 | for (final JsonNode objNode : authoritiesNode) { 70 | if (objNode.isArray()) { 71 | ArrayNode arrayNode = (ArrayNode) objNode; 72 | for (JsonNode elementNode : arrayNode) { 73 | UserAuthority userAuthority = mapper.readValue(elementNode.traverse(mapper), UserAuthority.class); 74 | userAuthorities.add(userAuthority); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | return userAuthorities; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/templates/consent.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | Consent required 10 | 15 | 21 | 22 | 23 |
24 |
25 |

App permissions

26 |
27 |
28 |
29 |

30 | The application 31 | 32 | wants to access your account 33 | 34 |

35 |
36 |
37 |
38 |

The following permissions are requested by the above app.
Please review 39 | these and consent if you approve.

40 |
41 |
42 |
43 |
44 | 45 | 46 | 47 |
48 | 53 | 54 |

55 |
56 | 57 |

You have already granted the following permissions to the above app:

58 |
59 | 64 | 65 |

66 |
67 | 68 |
69 | 72 |
73 |
74 | 77 |
78 |
79 |
80 |
81 |
82 |
83 |

84 | 85 | Your consent to provide access is required. 86 |
If you do not approve, click Cancel, in which case no information will be shared with the app. 87 |
88 |

89 |
90 |
91 |
92 | 93 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/configuration/federated/identity/FederatedIdentityConfigurer.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.configuration.federated.identity; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; 8 | import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; 9 | import org.springframework.security.oauth2.core.oidc.user.OidcUser; 10 | import org.springframework.security.oauth2.core.user.OAuth2User; 11 | import org.springframework.util.Assert; 12 | 13 | public final class FederatedIdentityConfigurer extends AbstractHttpConfigurer { 14 | 15 | private String loginPageUrl = "/login"; 16 | 17 | private String authorizationRequestUri; 18 | 19 | private Consumer oauth2UserHandler; 20 | 21 | private Consumer oidcUserHandler; 22 | 23 | /** 24 | * @param loginPageUrl The URL of the login page, defaults to {@code "/login"} 25 | * @return This configurer for additional configuration 26 | */ 27 | public FederatedIdentityConfigurer loginPageUrl(String loginPageUrl) { 28 | Assert.hasText(loginPageUrl, "loginPageUrl cannot be empty"); 29 | this.loginPageUrl = loginPageUrl; 30 | return this; 31 | } 32 | 33 | /** 34 | * @param authorizationRequestUri The authorization request URI for initiating 35 | * the login flow with an external IDP, defaults to {@code "/oauth2/authorization/{registrationId}"} 36 | * @return This configurer for additional configuration 37 | */ 38 | public FederatedIdentityConfigurer authorizationRequestUri(String authorizationRequestUri) { 39 | Assert.hasText(authorizationRequestUri, "authorizationRequestUri cannot be empty"); 40 | this.authorizationRequestUri = authorizationRequestUri; 41 | return this; 42 | } 43 | 44 | /** 45 | * @param oauth2UserHandler The {@link Consumer} for performing JIT account provisioning with an OAuth 2.0 IDP 46 | * @return This configurer for additional configuration 47 | */ 48 | public FederatedIdentityConfigurer oauth2UserHandler(Consumer oauth2UserHandler) { 49 | Assert.notNull(oauth2UserHandler, "oauth2UserHandler cannot be null"); 50 | this.oauth2UserHandler = oauth2UserHandler; 51 | return this; 52 | } 53 | 54 | /** 55 | * @param oidcUserHandler The {@link Consumer} for performing JIT account provisioning with an OpenID Connect 1.0 IDP 56 | * @return This configurer for additional configuration 57 | */ 58 | public FederatedIdentityConfigurer oidcUserHandler(Consumer oidcUserHandler) { 59 | Assert.notNull(oidcUserHandler, "oidcUserHandler cannot be null"); 60 | this.oidcUserHandler = oidcUserHandler; 61 | return this; 62 | } 63 | 64 | // @formatter:off 65 | @Override 66 | public void init(HttpSecurity http) throws Exception { 67 | ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class); 68 | ClientRegistrationRepository clientRegistrationRepository = applicationContext.getBean(ClientRegistrationRepository.class); 69 | FederatedIdentityAuthenticationEntryPoint authenticationEntryPoint = 70 | new FederatedIdentityAuthenticationEntryPoint(this.loginPageUrl, clientRegistrationRepository); 71 | if (this.authorizationRequestUri != null) { 72 | authenticationEntryPoint.setAuthorizationRequestUri(this.authorizationRequestUri); 73 | } 74 | 75 | FederatedIdentityAuthenticationSuccessHandler authenticationSuccessHandler = new FederatedIdentityAuthenticationSuccessHandler(); 76 | if (this.oauth2UserHandler != null) { 77 | authenticationSuccessHandler.setOAuth2UserHandler(this.oauth2UserHandler); 78 | } 79 | if (this.oidcUserHandler != null) { 80 | authenticationSuccessHandler.setOidcUserHandler(this.oidcUserHandler); 81 | } 82 | 83 | http 84 | .exceptionHandling(exceptionHandling -> exceptionHandling.authenticationEntryPoint(authenticationEntryPoint)) 85 | .oauth2Login(oauth2Login -> { 86 | oauth2Login.successHandler(authenticationSuccessHandler); 87 | if (this.authorizationRequestUri != null) { 88 | String baseUri = this.authorizationRequestUri.replace("/{registrationId}", ""); 89 | oauth2Login.authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint.baseUri(baseUri) 90 | ); 91 | } 92 | }); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /SpringResourceServer/src/main/java/pk/training/basit/converter/jwt/CustomJwtGrantedAuthoritiesConverter.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.converter.jwt; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Collection; 6 | import java.util.Collections; 7 | 8 | import org.apache.commons.logging.Log; 9 | import org.apache.commons.logging.LogFactory; 10 | import org.springframework.core.convert.converter.Converter; 11 | import org.springframework.core.log.LogMessage; 12 | import org.springframework.security.core.GrantedAuthority; 13 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 14 | import org.springframework.security.oauth2.jwt.Jwt; 15 | import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; 16 | import org.springframework.util.Assert; 17 | import org.springframework.util.StringUtils; 18 | 19 | public class CustomJwtGrantedAuthoritiesConverter implements Converter> { 20 | 21 | private final Log logger = LogFactory.getLog(getClass()); 22 | 23 | private static final String DEFAULT_AUTHORITY_PREFIX = "SCOPE_"; 24 | 25 | private static final Collection WELL_KNOWN_AUTHORITIES_CLAIM_NAMES = Arrays.asList("scope", "scp"); 26 | 27 | private String authorityPrefix = DEFAULT_AUTHORITY_PREFIX; 28 | 29 | private String authoritiesClaimName; 30 | 31 | /** 32 | * Extract {@link GrantedAuthority}s from the given {@link Jwt}. 33 | * @param jwt The {@link Jwt} token 34 | * @return The {@link GrantedAuthority authorities} read from the token scopes 35 | */ 36 | @Override 37 | public Collection convert(Jwt jwt) { 38 | Collection grantedAuthorities = new ArrayList<>(); 39 | for (String authority : getAuthorities(jwt)) { 40 | grantedAuthorities.add(new SimpleGrantedAuthority(this.authorityPrefix + authority)); 41 | } 42 | return grantedAuthorities; 43 | } 44 | 45 | /** 46 | * Sets the prefix to use for {@link GrantedAuthority authorities} mapped by this 47 | * converter. Defaults to 48 | * {@link JwtGrantedAuthoritiesConverter#DEFAULT_AUTHORITY_PREFIX}. 49 | * @param authorityPrefix The authority prefix 50 | * @since 5.2 51 | */ 52 | public void setAuthorityPrefix(String authorityPrefix) { 53 | //Assert.notNull(authorityPrefix, "authorityPrefix cannot be null"); 54 | this.authorityPrefix = authorityPrefix; 55 | } 56 | 57 | /** 58 | * Sets the name of token claim to use for mapping {@link GrantedAuthority 59 | * authorities} by this converter. Defaults to 60 | * {@link JwtGrantedAuthoritiesConverter#WELL_KNOWN_AUTHORITIES_CLAIM_NAMES}. 61 | * @param authoritiesClaimName The token claim name to map authorities 62 | * @since 5.2 63 | */ 64 | public void setAuthoritiesClaimName(String authoritiesClaimName) { 65 | Assert.hasText(authoritiesClaimName, "authoritiesClaimName cannot be empty"); 66 | this.authoritiesClaimName = authoritiesClaimName; 67 | } 68 | 69 | private String getAuthoritiesClaimName(Jwt jwt) { 70 | if (this.authoritiesClaimName != null) { 71 | return this.authoritiesClaimName; 72 | } 73 | for (String claimName : WELL_KNOWN_AUTHORITIES_CLAIM_NAMES) { 74 | if (jwt.hasClaim(claimName)) { 75 | return claimName; 76 | } 77 | } 78 | return null; 79 | } 80 | 81 | private Collection getAuthorities(Jwt jwt) { 82 | String claimName = getAuthoritiesClaimName(jwt); 83 | if (claimName == null) { 84 | this.logger.trace("Returning no authorities since could not find any claims that might contain scopes"); 85 | return Collections.emptyList(); 86 | } 87 | if (this.logger.isTraceEnabled()) { 88 | this.logger.trace(LogMessage.format("Looking for scopes in claim %s", claimName)); 89 | } 90 | Object authorities = jwt.getClaim(claimName); 91 | if (authorities instanceof String) { 92 | if (StringUtils.hasText((String) authorities)) { 93 | return Arrays.asList(((String) authorities).split(" ")); 94 | } 95 | return Collections.emptyList(); 96 | } 97 | if (authorities instanceof Collection) { 98 | return castAuthoritiesToCollection(authorities); 99 | } 100 | return Collections.emptyList(); 101 | } 102 | 103 | @SuppressWarnings("unchecked") 104 | private Collection castAuthoritiesToCollection(Object authorities) { 105 | return (Collection) authorities; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/service/impl/UserPrincipalServiceImpl.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | import org.springframework.transaction.annotation.Transactional; 5 | 6 | import pk.training.basit.jpa.entity.UserPrincipal; 7 | import pk.training.basit.jpa.repository.UserPrincipalRepository; 8 | import pk.training.basit.service.UserPrincipalService; 9 | 10 | /** 11 | * Services are the next layer above repositories. Services encapsulate the business logic of the application and consume other 12 | * services and repositories but do not consume resources in higher application layers like controllers (again, something that 13 | * Spring does not actively enforce). Services are marked with the @Service annotation, making them eligible for automatic 14 | * instantiation and dependency injection, among other benefits. Like repositories, services are created from interfaces so that 15 | * dependent resources may program against an interface. This pattern of basing each layer on a set of interfaces allows each layer 16 | * to be tested in isolation from all the other layers. From a transactional point of view, the execution of a service method from a 17 | * higher layer (such as a controller) can be thought of as a transactional unit of work. It may perform several operations on 18 | * multiple repositories and other services in the context that all operations must either succeed or fail as a single unit. When a 19 | * service method is executed from another service method, it is generally thought of as belonging to the same unit of work that the 20 | * calling method belongs to. 21 | * 22 | * It should be noted that this concept of unit of work does not imply that it can always be handled with traditional relational 23 | * database transactions. The operations performed during a unit of work may have multiple consequences across different data stores 24 | * or file media. These operations may include transmission of intra- or inter-application messages, e-mails, text messages, or 25 | * mobile notifications that in most cases cannot be rolled back. 26 | * 27 | * Some developers do not like to use the term �service� to describe this layer of the application, as that can sometimes be confused 28 | * with web services. What you call your business logic layer doesn�t matter. You don�t even have to use the @Service annotation. 29 | * You could instead use the @Component annotation or a custom annotation meta-annotated with @Component. What you call it and how 30 | * you mark it does not change its purpose. 31 | * 32 | * @author basit.ahmed 33 | * 34 | */ 35 | @Service 36 | public class UserPrincipalServiceImpl implements UserPrincipalService { 37 | 38 | private final UserPrincipalRepository userPrincipalRepository; 39 | 40 | /** 41 | * The constructor is annotated with @Autowired, meaning that it injects the UserPrincipalRepository 42 | * implementation. This annotation can be omitted; Spring automatically injects any declared dependency since version 4.3. 43 | */ 44 | public UserPrincipalServiceImpl(UserPrincipalRepository userPrincipalRepository) { 45 | this.userPrincipalRepository = userPrincipalRepository; 46 | } 47 | 48 | /** 49 | * Notice that the implementation lacks any validation related annotations. This is the way it should be because the interface 50 | * contains that contract. 51 | * 52 | * The supports method indicates that this AuthenticationProvider can authenticate using only 53 | * UsernamePasswordAuthenticationTokens. After casting the Authentication to a UsernamePasswordAuthenticationToken and 54 | * retrieving the username and password, authenticate erases the plain-text password stored in the token so that it can�t 55 | * accidentally leak anywhere. It then retrieves the UserPrincipal and runs through the standard checks it previously ran 56 | * through. After the user identity has been confirmed, it sets the authenticated flag to true (in bold) to confirm the 57 | * authentication succeeded. 58 | */ 59 | @Override 60 | @Transactional 61 | public UserPrincipal loadUserByUsername(String username) { 62 | 63 | UserPrincipal principal = userPrincipalRepository.getByUsername(username); 64 | 65 | // make sure the authorities and password are loaded 66 | principal.getAuthorities().size(); 67 | principal.getPassword(); 68 | return principal; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/controller/web/AuthorizationConsentController.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.controller.web; 2 | 3 | import java.security.Principal; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.Map; 8 | import java.util.Set; 9 | import java.util.stream.Collectors; 10 | 11 | import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; 12 | import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent; 13 | import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; 14 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; 15 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; 16 | import org.springframework.stereotype.Controller; 17 | import org.springframework.ui.Model; 18 | import org.springframework.util.StringUtils; 19 | import org.springframework.web.bind.annotation.GetMapping; 20 | import org.springframework.web.bind.annotation.RequestParam; 21 | 22 | @Controller 23 | public class AuthorizationConsentController { 24 | 25 | private final RegisteredClientRepository registeredClientRepository; 26 | private final OAuth2AuthorizationConsentService authorizationConsentService; 27 | 28 | public AuthorizationConsentController(RegisteredClientRepository registeredClientRepository, 29 | OAuth2AuthorizationConsentService authorizationConsentService) { 30 | this.registeredClientRepository = registeredClientRepository; 31 | this.authorizationConsentService = authorizationConsentService; 32 | } 33 | 34 | @GetMapping(value = "/oauth2/consent") 35 | public String consent(Principal principal, Model model, 36 | @RequestParam(OAuth2ParameterNames.CLIENT_ID) String clientId, 37 | @RequestParam(OAuth2ParameterNames.SCOPE) String scope, 38 | @RequestParam(OAuth2ParameterNames.STATE) String state) { 39 | 40 | // Remove scopes that were already approved 41 | Set scopesToApprove = new HashSet<>(); 42 | Set previouslyApprovedScopes = new HashSet<>(); 43 | RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId); 44 | OAuth2AuthorizationConsent currentAuthorizationConsent = authorizationConsentService.findById(registeredClient.getId(), principal.getName()); 45 | Set authorizedScopes; 46 | if (currentAuthorizationConsent != null) { 47 | authorizedScopes = currentAuthorizationConsent.getScopes(); 48 | } else { 49 | authorizedScopes = Collections.emptySet(); 50 | } 51 | for (String requestedScope : StringUtils.delimitedListToStringArray(scope, " ")) { 52 | if (authorizedScopes.contains(requestedScope)) { 53 | previouslyApprovedScopes.add(requestedScope); 54 | } else { 55 | scopesToApprove.add(requestedScope); 56 | } 57 | } 58 | 59 | String registeredClientName = registeredClient.getClientName(); 60 | 61 | model.addAttribute("clientId", clientId); 62 | model.addAttribute("clientName", registeredClientName); 63 | model.addAttribute("state", state); 64 | model.addAttribute("scopes", withDescription(scopesToApprove)); 65 | model.addAttribute("previouslyApprovedScopes", withDescription(previouslyApprovedScopes)); 66 | model.addAttribute("principalName", principal.getName()); 67 | 68 | return "consent-customized"; 69 | } 70 | 71 | private static Set withDescription(Set scopes) { 72 | return scopes 73 | .stream() 74 | .map(ScopeWithDescription::new) 75 | .collect(Collectors.toSet()); 76 | } 77 | 78 | public static class ScopeWithDescription { 79 | 80 | private static final String DEFAULT_DESCRIPTION = "UNKNOWN SCOPE - We cannot provide information about this permission, use caution when granting this."; 81 | private static final Map scopeDescriptions = new HashMap<>(); 82 | 83 | static { 84 | scopeDescriptions.put("message.read", "This application will be able to read your message."); 85 | scopeDescriptions.put("message.write", "This application will be able to add new messages. It will also be able to edit and delete existing messages."); 86 | scopeDescriptions.put("other.scope", "This is another scope example of a scope description."); 87 | } 88 | 89 | public final String scope; 90 | public final String description; 91 | 92 | ScopeWithDescription(String scope) { 93 | this.scope = scope; 94 | this.description = scopeDescriptions.getOrDefault(scope, DEFAULT_DESCRIPTION); 95 | } 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.servlet.context-path = /springauthserver 2 | server.port = 9000 3 | 4 | management.endpoints.web.exposure.include = health,info 5 | 6 | spring.config.import = classpath:version.properties,classpath:federated-identity.properties 7 | 8 | ######################################################################################################################### 9 | ########################################### Spring Boot JPA Properties ################################################## 10 | ######################################################################################################################### 11 | 12 | spring.jpa.generate-ddl = false 13 | spring.jpa.show-sql = true 14 | spring.jpa.database-platform = org.hibernate.dialect.H2Dialect 15 | 16 | ############################################################################################################################## 17 | ####################################### Spring Boot JPA Hiberate Properties ################################################## 18 | ############################################################################################################################## 19 | 20 | spring.jpa.hibernate.ddl-auto = none 21 | 22 | # to format SQL generated in a visually pleasing manner 23 | spring.jpa.properties.hibernate.format-sql = true 24 | spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl 25 | 26 | #spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect 27 | 28 | spring.jpa.properties.hibernate.jdbc.time_zone = UTC 29 | 30 | # Batch 31 | spring.jpa.properties.hibernate.jdbc.batch_size = 20 32 | spring.jpa.properties.hibernate.jdbc.fetch_size = 200 33 | spring.jpa.properties.hibernate.jdbc.batch_versioned_data = true 34 | spring.jpa.properties.hibernate.order_inserts = true 35 | spring.jpa.properties.hibernate.order_updates = true 36 | 37 | ########################################################################################################################## 38 | ############################################### Database Properties ###################################################### 39 | ########################################################################################################################## 40 | 41 | spring.datasource.url = jdbc:h2:mem:testdb;;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false 42 | spring.datasource.driverClassName = org.h2.Driver 43 | spring.datasource.username = sa 44 | spring.datasource.password = password 45 | spring.sql.init.schema-locations = classpath:/org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql,\ 46 | classpath:/org/springframework/security/oauth2/server/authorization/oauth2-authorization-consent-schema.sql,\ 47 | classpath:/org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql,\ 48 | classpath:/database/scripts/schema-h2.sql 49 | 50 | spring.sql.init.data-locations = classpath:/database/scripts/test-data.sql 51 | spring.datasource.sql-script-encoding = UTF-8 52 | spring.h2.console.enabled = true 53 | 54 | # http://127.0.0.1:9000/springauthserver/h2-console 55 | spring.h2.console.path = /h2-console 56 | 57 | 58 | ########################################################################################################################## 59 | #################################################### OAuth2 Token ######################################################## 60 | ########################################################################################################################## 61 | 62 | oauth2.access.token.time = 1 63 | oauth2.access.token.time.unit = day 64 | 65 | oauth2.refresh.token.time = 4 66 | oauth2.refresh.token.time.unit = day 67 | 68 | oauth2.token.issuer = http://127.0.0.1:9000/springauthserver 69 | 70 | ########################################################################################################################## 71 | #################################################### Logging ############################################################# 72 | ########################################################################################################################## 73 | 74 | logging.level.root = INFO 75 | logging.level.org.springframework.web = INFO 76 | logging.level.org.springframework.security = INFO 77 | logging.level.org.springframework.security.oauth2 = INFO 78 | 79 | ################################################################### 80 | #################### Internationalization ######################### 81 | #################################################################### 82 | spring.messages.basename = i18n/errors,i18n/messages,i18n/titles,i18n/validation,org/springframework/security/messages 83 | spring.messages.fallback-to-system-locale = true 84 | 85 | #################################################################### 86 | ######################### Locale ################################### 87 | #################################################################### 88 | spring.web.locale = en_US 89 | spring.web.locale-resolver = fixed 90 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/resources/templates/consent-customized.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 23 | 24 | 25 | 26 |
27 | 28 |
29 | 30 |
31 |
32 |
33 |
34 |
35 | 36 | 39 | 40 |
41 |
42 |
43 | The application 44 | 45 | wants to access your application account 46 |
47 |
48 |
49 | 50 |
51 |
52 |
53 | 54 | 55 |
56 |
57 |
58 | 59 |
60 |
61 |

62 | This will allow 63 | 64 | to: 65 |

66 |
67 |
68 | 69 |
70 |
71 |
    72 |
  • 73 |
    74 |
    75 | memorynotfound logo 76 |
    77 |
    78 | 79 |
    80 |
    81 |
  • 82 |
83 |
84 |
85 | 86 |
87 |
88 |

89 | Make sure you trust 90 |

91 |
92 |
93 | 94 |
95 |
96 | 120 |
121 |
122 |
123 |
124 | 125 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/src/main/java/pk/training/basit/config/WebClientConfig.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.config; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.function.Function; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 13 | import org.springframework.security.core.Authentication; 14 | import org.springframework.security.core.userdetails.User; 15 | import org.springframework.security.oauth2.client.OAuth2AuthorizationContext; 16 | import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; 17 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; 18 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider; 19 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; 20 | import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; 21 | import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager; 22 | import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; 23 | import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction; 24 | import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; 25 | import org.springframework.util.CollectionUtils; 26 | import org.springframework.util.StringUtils; 27 | import org.springframework.web.reactive.function.client.WebClient; 28 | 29 | @Configuration 30 | public class WebClientConfig { 31 | 32 | @Bean 33 | WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) { 34 | 35 | ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = 36 | new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); 37 | 38 | return WebClient.builder().apply(oauth2Client.oauth2Configuration()).build(); 39 | } 40 | 41 | @Bean 42 | OAuth2AuthorizedClientManager authorizedClientManager(ClientRegistrationRepository clientRegistrationRepository, 43 | OAuth2AuthorizedClientRepository authorizedClientRepository) { 44 | 45 | OAuth2AuthorizedClientProvider authorizedClientProvider = 46 | OAuth2AuthorizedClientProviderBuilder.builder() 47 | .authorizationCode() 48 | .refreshToken() 49 | .clientCredentials() 50 | .password() 51 | .build(); 52 | 53 | DefaultOAuth2AuthorizedClientManager authorizedClientManager = new DefaultOAuth2AuthorizedClientManager( 54 | clientRegistrationRepository, authorizedClientRepository); 55 | 56 | authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); 57 | 58 | // Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters, 59 | // map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()` 60 | authorizedClientManager.setContextAttributesMapper(contextAttributesMapper()); 61 | 62 | return authorizedClientManager; 63 | } 64 | 65 | private Function> contextAttributesMapper() { 66 | 67 | return authorizeRequest -> { 68 | 69 | Map contextAttributes = Collections.emptyMap(); 70 | 71 | HttpServletRequest servletRequest = authorizeRequest.getAttribute(HttpServletRequest.class.getName()); 72 | String username = servletRequest.getParameter(OAuth2ParameterNames.USERNAME); 73 | String password = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD); 74 | String scope = servletRequest.getParameter(OAuth2ParameterNames.SCOPE); 75 | if (StringUtils.hasText(scope)) { 76 | contextAttributes = new HashMap<>(); 77 | contextAttributes.put(OAuth2AuthorizationContext.REQUEST_SCOPE_ATTRIBUTE_NAME, 78 | StringUtils.delimitedListToStringArray(scope, " ")); 79 | } 80 | 81 | if (!StringUtils.hasText(username) && !StringUtils.hasText(password)) { 82 | Authentication authentication = authorizeRequest.getPrincipal(); 83 | if (authentication instanceof UsernamePasswordAuthenticationToken) { 84 | UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication; 85 | Object principal = token.getPrincipal(); 86 | username = token.getName(); 87 | password = (String) token.getCredentials(); 88 | if (principal instanceof User) { 89 | User user = (User) principal; 90 | username = user.getUsername(); 91 | } 92 | } 93 | } 94 | 95 | if (StringUtils.hasText(username) && StringUtils.hasText(password)) { 96 | 97 | if (CollectionUtils.isEmpty(contextAttributes)) { 98 | contextAttributes = new HashMap<>(); 99 | } 100 | 101 | // `PasswordOAuth2AuthorizedClientProvider` requires both attributes 102 | contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, username); 103 | contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, password); 104 | 105 | } 106 | 107 | return contextAttributes; 108 | }; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /SpringResourceServer/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /SpringAuthorizationServerClient/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /SpringAuthorizationServer/src/main/java/pk/training/basit/jpa/entity/UserPrincipal.java: -------------------------------------------------------------------------------- 1 | package pk.training.basit.jpa.entity; 2 | 3 | import java.util.Collections; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | 7 | import javax.persistence.Basic; 8 | import javax.persistence.CollectionTable; 9 | import javax.persistence.Column; 10 | import javax.persistence.ElementCollection; 11 | import javax.persistence.Embedded; 12 | import javax.persistence.Entity; 13 | import javax.persistence.FetchType; 14 | import javax.persistence.GeneratedValue; 15 | import javax.persistence.GenerationType; 16 | import javax.persistence.Id; 17 | import javax.persistence.JoinColumn; 18 | import javax.persistence.Table; 19 | import javax.persistence.Transient; 20 | import javax.persistence.UniqueConstraint; 21 | 22 | import org.springframework.security.core.CredentialsContainer; 23 | import org.springframework.security.core.userdetails.UserDetails; 24 | 25 | import pk.training.basit.jpa.audit.AuditDeletedDate; 26 | 27 | /** 28 | * The first two and most basic JPA mapping annotations are @javax.persistence.Entity and @javax.persistence.Table. @Entity marks a 29 | * class to indicate that it is an entity. Every entity must have this annotation. By default, an entity name is equal to the 30 | * unqualified entity class name, so the following pk.training.basit.entities.Book class has an entity name of Author. 31 | * 32 | * The table name to which an entity maps defaults is the entity name. So the default table name for UserPrincipal is UserPrincipal. 33 | * uniqueConstraints is a special attribute used exclusively for schema generation. JPA providers can automatically generate 34 | * database schema based off of your entities, and this attribute enables you to indicate that a particular column or columns should 35 | * form a unique constraint. 36 | * As of JPA 2.1, you can also use the indexes attribute to specify indexes that JPA should create when using schema generation. 37 | */ 38 | @Entity 39 | @Table( 40 | uniqueConstraints = { 41 | @UniqueConstraint( 42 | name = "UserPrincipal_Username", 43 | columnNames = "Username" 44 | ) 45 | } 46 | ) 47 | /** 48 | * When you design your system, ultimately you need to decide whether you want to couple the user object for persistence purposes 49 | * with the user object for authentication and authorization purposes. The advantage to separating them is that you really don’t 50 | * need (or even want) a mutable user object carried around in the security context, and keeping them separate enforces this mantra. 51 | * However, the advantage to making them the same object is that you don't have to do as much work to embed the user entity in other 52 | * entities. Ultimately, only you can decide the approach that works best for you. 53 | * 54 | * For simplicity, the Customer Support application combines the UserDetails implementation and the entity in the same object. The 55 | * changes to UserPrincipal are pretty simple. It now implements UserDetails instead of Authentication and also implements 56 | * org.springframework.security.core.CredentialsContainer so that Spring Security clears the password when the authentication process 57 | * is complete. 58 | */ 59 | public class UserPrincipal implements UserDetails, CredentialsContainer, Cloneable { 60 | 61 | private static final long serialVersionUID = 1L; 62 | 63 | /** 64 | * One of the first things you must do when mapping JPA entities is create surrogate keys, also called primary keys or IDs, for 65 | * those entities. Every entity should have an ID, which can be one field (and thus a single column) or multiple fields (and thus 66 | * multiple columns). As a result, you have many different approaches for mapping an ID. 67 | * 68 | * First, you can mark any JavaBean property with @javax.persistence.Id. This annotation can go on the private field or the 69 | * public accessor method and indicates that the property is the entity’s surrogate key. The property may be any Java primitive, 70 | * primitive wrapper, String, java.util.Date, java.sql.Date, java.math.BigInteger, or java.math.BigDecimal. 71 | * 72 | * If your entity class does not have an @Id property, the JPA provider looks for a property named id (with accessor getId and 73 | * mutator setId) and uses it automatically. This property must also be a primitive, primitive wrapper, String, java.util.Date, 74 | * java.sql.Date, BigInteger, or BigDecimal. 75 | * 76 | * You can, whenever you want, create an entity with an ID that is manually generated and assigned. However, this is rarely 77 | * desired because it requires extra, repetitive, unnecessary work. Typically, you want your entity IDs to be automatically 78 | * generated in some manner. You can accomplish this using the @javax.persistence.GeneratedValue annotation. @GeneratedValue 79 | * enables you to specify a generation strategy and, if necessary, a generator name. For example, the Book and Author entity IDs 80 | * use javax.persistence.GenerationType.IDENTITY to indicate that the database column the ID is stored in can generate its own 81 | * value automatically. 82 | * 83 | * This is compatible with MySQL AUTO_INCREMENT columns, Microsoft SQL Server and Sybase IDENTITY columns, PostgreSQL SERIAL and 84 | * DEFAULT NEXTVAL() columns, Oracle DEFAULT SYS_GUID() columns, and more. You cannot use GenerationType.IDENTITY with databases 85 | * that do not support the auto-generation of column values, but all the most common relational databases support this. 86 | * 87 | * @return 88 | */ 89 | @Id 90 | @Column(name = "UserId") 91 | @GeneratedValue(strategy = GenerationType.IDENTITY) 92 | private Long id; 93 | 94 | @Basic 95 | private String username; 96 | 97 | /** 98 | * You can use @Basic’s optional attribute to indicate that the property may be null. (This is only a hint and is useful for 99 | * schema generation.) This is ignored for primitives, which may never be null. 100 | */ 101 | @Basic(fetch = FetchType.LAZY) 102 | @Column(name = "HashedPassword") 103 | private String hashedPassword; 104 | 105 | private boolean enabled; 106 | private boolean accountNonExpired; 107 | private boolean credentialsNonExpired; 108 | private boolean accountNonLocked; 109 | 110 | // @CollectionTable in UserPrincipal maps UserAuthority to the UserPrincipalAuthority table. 111 | @ElementCollection(fetch = FetchType.LAZY) 112 | @CollectionTable( 113 | name = "UserPrincipalAuthority", 114 | joinColumns = { 115 | @JoinColumn( 116 | name = "UserId", 117 | referencedColumnName = "UserId" 118 | ) 119 | } 120 | ) 121 | private Set authorities = new HashSet<>(); 122 | 123 | @Embedded 124 | private AuditDeletedDate audit = new AuditDeletedDate(); 125 | 126 | public UserPrincipal() { 127 | 128 | } 129 | 130 | public UserPrincipal(Long id, String username, String password, Set authorities) { 131 | this(id, username, password, true, true, true, true, authorities, null); 132 | } 133 | 134 | public UserPrincipal(Long id, String username, String password, boolean enabled, boolean accountNonExpired, 135 | boolean credentialsNonExpired, boolean accountNonLocked, Set authorities, AuditDeletedDate audit) { 136 | this.id = id; 137 | this.username = username; 138 | this.hashedPassword = password; 139 | this.enabled = enabled; 140 | this.accountNonExpired = accountNonExpired; 141 | this.credentialsNonExpired = credentialsNonExpired; 142 | this.accountNonLocked = accountNonLocked; 143 | this.authorities = Collections.unmodifiableSet(authorities); 144 | this.audit = audit; 145 | } 146 | 147 | public Long getId() { 148 | return this.id; 149 | } 150 | 151 | public void setId(Long id) { 152 | this.id = id; 153 | } 154 | 155 | public String getUsername() { 156 | return this.username; 157 | } 158 | 159 | public void setUsername(String username) { 160 | this.username = username; 161 | } 162 | 163 | public String getHashedPassword() { 164 | return this.hashedPassword; 165 | } 166 | 167 | public void setHashedPassword(String password) { 168 | this.hashedPassword = password; 169 | } 170 | 171 | @Transient 172 | @Override 173 | public String getPassword() { 174 | return this.getHashedPassword() == null ? null : this.getHashedPassword(); 175 | } 176 | 177 | @Override 178 | public void eraseCredentials() { 179 | this.hashedPassword = null; 180 | } 181 | 182 | @Override 183 | public Set getAuthorities() { 184 | return this.authorities; 185 | } 186 | 187 | public void setAuthorities(Set authorities) { 188 | this.authorities = authorities; 189 | } 190 | 191 | @Override 192 | public boolean isAccountNonExpired() { 193 | return this.accountNonExpired; 194 | } 195 | 196 | public void setAccountNonExpired(boolean accountNonExpired) { 197 | this.accountNonExpired = accountNonExpired; 198 | } 199 | 200 | @Override 201 | public boolean isAccountNonLocked() { 202 | return this.accountNonLocked; 203 | } 204 | 205 | public void setAccountNonLocked(boolean accountNonLocked) { 206 | this.accountNonLocked = accountNonLocked; 207 | } 208 | 209 | @Override 210 | public boolean isCredentialsNonExpired() { 211 | return this.credentialsNonExpired; 212 | } 213 | 214 | public void setCredentialsNonExpired(boolean credentialsNonExpired) { 215 | this.credentialsNonExpired = credentialsNonExpired; 216 | } 217 | 218 | @Override 219 | public boolean isEnabled() { 220 | return this.enabled; 221 | } 222 | 223 | public void setEnabled(boolean enabled) { 224 | this.enabled = enabled; 225 | } 226 | 227 | public AuditDeletedDate getAudit() { 228 | return audit; 229 | } 230 | 231 | public void setAudit(AuditDeletedDate audit) { 232 | this.audit = audit; 233 | } 234 | 235 | @Override 236 | public int hashCode() { 237 | return this.username.hashCode(); 238 | } 239 | 240 | @Override 241 | public boolean equals(Object other) { 242 | return other instanceof UserPrincipal && ((UserPrincipal)other).id == this.id; 243 | } 244 | 245 | @Override 246 | protected UserPrincipal clone() { 247 | try { 248 | return (UserPrincipal)super.clone(); 249 | } catch (CloneNotSupportedException e) { 250 | throw new RuntimeException(e); // not possible 251 | } 252 | } 253 | 254 | @Override 255 | public String toString() { 256 | return this.username; 257 | } 258 | 259 | } 260 | --------------------------------------------------------------------------------