From 9b4ee4aae3281999addc3426455288707962c3dc Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Fri, 19 Jun 2020 23:06:12 +0530 Subject: [PATCH] BAEL-4019: Exploring Java Security frameworks --- java-security/.gitignore | 4 + java-security/README.md | 8 ++ java-security/apache-shiro/.gitignore | 4 + java-security/apache-shiro/pom.xml | 40 ++++++++ .../java/com/baeldung/shiro/CustomRealm.java | 92 ++++++++++++++++++ .../com/baeldung/shiro/ShiroApplication.java | 32 +++++++ .../shiro/controllers/ShiroController.java | 95 +++++++++++++++++++ .../shiro/models/UserCredentials.java | 28 ++++++ .../src/main/resources/application.yml | 16 ++++ .../src/main/resources/templates/home.ftl | 19 ++++ .../src/main/resources/templates/index.ftl | 10 ++ .../src/main/resources/templates/login.ftl | 25 +++++ .../com/baeldung/shiro/SpringContextTest.java | 18 ++++ java-security/pom.xml | 22 +++++ java-security/spring-security/.gitignore | 4 + java-security/spring-security/pom.xml | 31 ++++++ .../baeldung/springsecurity/Application.java | 12 +++ .../springsecurity/config/SecurityConfig.java | 45 +++++++++ .../springsecurity/web/SpringController.java | 79 +++++++++++++++ .../src/main/resources/application.yml | 12 +++ .../src/main/resources/templates/home.ftl | 20 ++++ .../src/main/resources/templates/index.ftl | 10 ++ .../src/main/resources/templates/login.ftl | 26 +++++ .../springsecurity/SpringContextTest.java | 17 ++++ 24 files changed, 669 insertions(+) create mode 100644 java-security/.gitignore create mode 100644 java-security/README.md create mode 100644 java-security/apache-shiro/.gitignore create mode 100644 java-security/apache-shiro/pom.xml create mode 100644 java-security/apache-shiro/src/main/java/com/baeldung/shiro/CustomRealm.java create mode 100644 java-security/apache-shiro/src/main/java/com/baeldung/shiro/ShiroApplication.java create mode 100644 java-security/apache-shiro/src/main/java/com/baeldung/shiro/controllers/ShiroController.java create mode 100644 java-security/apache-shiro/src/main/java/com/baeldung/shiro/models/UserCredentials.java create mode 100644 java-security/apache-shiro/src/main/resources/application.yml create mode 100644 java-security/apache-shiro/src/main/resources/templates/home.ftl create mode 100644 java-security/apache-shiro/src/main/resources/templates/index.ftl create mode 100644 java-security/apache-shiro/src/main/resources/templates/login.ftl create mode 100644 java-security/apache-shiro/src/test/java/com/baeldung/shiro/SpringContextTest.java create mode 100644 java-security/pom.xml create mode 100644 java-security/spring-security/.gitignore create mode 100644 java-security/spring-security/pom.xml create mode 100644 java-security/spring-security/src/main/java/com/baeldung/springsecurity/Application.java create mode 100644 java-security/spring-security/src/main/java/com/baeldung/springsecurity/config/SecurityConfig.java create mode 100644 java-security/spring-security/src/main/java/com/baeldung/springsecurity/web/SpringController.java create mode 100644 java-security/spring-security/src/main/resources/application.yml create mode 100644 java-security/spring-security/src/main/resources/templates/home.ftl create mode 100644 java-security/spring-security/src/main/resources/templates/index.ftl create mode 100644 java-security/spring-security/src/main/resources/templates/login.ftl create mode 100644 java-security/spring-security/src/test/java/com/baeldung/springsecurity/SpringContextTest.java diff --git a/java-security/.gitignore b/java-security/.gitignore new file mode 100644 index 0000000000..020cda4898 --- /dev/null +++ b/java-security/.gitignore @@ -0,0 +1,4 @@ + +/.idea/ +/target/ +/apache-shiro.iml \ No newline at end of file diff --git a/java-security/README.md b/java-security/README.md new file mode 100644 index 0000000000..bdf020ac4c --- /dev/null +++ b/java-security/README.md @@ -0,0 +1,8 @@ +## Java Security + +This module contains articles about Java security frameworks + +### Relevant articles: + + + diff --git a/java-security/apache-shiro/.gitignore b/java-security/apache-shiro/.gitignore new file mode 100644 index 0000000000..020cda4898 --- /dev/null +++ b/java-security/apache-shiro/.gitignore @@ -0,0 +1,4 @@ + +/.idea/ +/target/ +/apache-shiro.iml \ No newline at end of file diff --git a/java-security/apache-shiro/pom.xml b/java-security/apache-shiro/pom.xml new file mode 100644 index 0000000000..ad8bf67afc --- /dev/null +++ b/java-security/apache-shiro/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + apache-shiro + apache-shiro + + + com.baeldung + java-security + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + org.apache.shiro + shiro-spring-boot-web-starter + ${apache-shiro-core-version} + + + org.apache.shiro + shiro-core + ${apache-shiro-core-version} + + + org.slf4j + jcl-over-slf4j + runtime + + + + + 1.5.3 + + + diff --git a/java-security/apache-shiro/src/main/java/com/baeldung/shiro/CustomRealm.java b/java-security/apache-shiro/src/main/java/com/baeldung/shiro/CustomRealm.java new file mode 100644 index 0000000000..d911f37c20 --- /dev/null +++ b/java-security/apache-shiro/src/main/java/com/baeldung/shiro/CustomRealm.java @@ -0,0 +1,92 @@ +package com.baeldung.shiro; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.SimpleAuthenticationInfo; +import org.apache.shiro.authc.UnknownAccountException; +import org.apache.shiro.authc.UsernamePasswordToken; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.authz.SimpleAuthorizationInfo; +import org.apache.shiro.realm.jdbc.JdbcRealm; +import org.apache.shiro.subject.PrincipalCollection; + +public class CustomRealm extends JdbcRealm { + + private Map credentials = new HashMap<>(); + private Map> roles = new HashMap<>(); + private Map> permissions = new HashMap<>(); + + { + credentials.put("Tom", "password"); + credentials.put("Jerry", "password"); + + roles.put("Jerry", new HashSet<>(Arrays.asList("ADMIN"))); + roles.put("Tom", new HashSet<>(Arrays.asList("USER"))); + + permissions.put("ADMIN", new HashSet<>(Arrays.asList("READ", "WRITE"))); + permissions.put("USER", new HashSet<>(Arrays.asList("READ"))); + } + + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { + + UsernamePasswordToken userToken = (UsernamePasswordToken) token; + + if (userToken.getUsername() == null || userToken.getUsername() + .isEmpty() || !credentials.containsKey(userToken.getUsername())) { + throw new UnknownAccountException("User doesn't exist"); + } + + return new SimpleAuthenticationInfo(userToken.getUsername(), credentials.get(userToken.getUsername()), getName()); + } + + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + Set roles = new HashSet<>(); + Set permissions = new HashSet<>(); + + for (Object user : principals) { + try { + roles.addAll(getRoleNamesForUser(null, (String) user)); + permissions.addAll(getPermissions(null, null, roles)); + } catch (SQLException e) { + e.printStackTrace(); + } + } + SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo(roles); + authInfo.setStringPermissions(permissions); + return authInfo; + } + + @Override + protected Set getRoleNamesForUser(Connection conn, String username) throws SQLException { + if (!roles.containsKey(username)) { + throw new SQLException("User doesn't exist"); + } + return roles.get(username); + } + + @Override + protected Set getPermissions(Connection conn, String username, Collection roles) throws SQLException { + Set userPermissions = new HashSet<>(); + + for (String role : roles) { + if (!permissions.containsKey(role)) { + throw new SQLException("Role doesn't exist"); + } + userPermissions.addAll(permissions.get(role)); + } + return userPermissions; + } + +} diff --git a/java-security/apache-shiro/src/main/java/com/baeldung/shiro/ShiroApplication.java b/java-security/apache-shiro/src/main/java/com/baeldung/shiro/ShiroApplication.java new file mode 100644 index 0000000000..16c50ff1c5 --- /dev/null +++ b/java-security/apache-shiro/src/main/java/com/baeldung/shiro/ShiroApplication.java @@ -0,0 +1,32 @@ +package com.baeldung.shiro; + +import org.apache.shiro.realm.Realm; +import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition; +import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class ShiroApplication { + + public static void main(String... args) { + SpringApplication.run(ShiroApplication.class, args); + } + + @Bean + public Realm realm() { + return new CustomRealm(); + } + + @Bean + public ShiroFilterChainDefinition shiroFilterChainDefinition() { + DefaultShiroFilterChainDefinition filter = new DefaultShiroFilterChainDefinition(); + + filter.addPathDefinition("/home", "authc"); + filter.addPathDefinition("/**", "anon"); + + return filter; + } + +} diff --git a/java-security/apache-shiro/src/main/java/com/baeldung/shiro/controllers/ShiroController.java b/java-security/apache-shiro/src/main/java/com/baeldung/shiro/controllers/ShiroController.java new file mode 100644 index 0000000000..8e9403d3d3 --- /dev/null +++ b/java-security/apache-shiro/src/main/java/com/baeldung/shiro/controllers/ShiroController.java @@ -0,0 +1,95 @@ +package com.baeldung.shiro.controllers; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.UsernamePasswordToken; +import org.apache.shiro.subject.Subject; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import com.baeldung.shiro.models.UserCredentials; + +@Controller +public class ShiroController { + + @GetMapping("/") + public String index() { + return "index"; + } + + @GetMapping("/login") + public String showLoginPage() { + return "login"; + } + + @PostMapping("/login") + public String doLogin(HttpServletRequest req, UserCredentials credentials, RedirectAttributes attr) { + + Subject subject = SecurityUtils.getSubject(); + + if (!subject.isAuthenticated()) { + UsernamePasswordToken token = new UsernamePasswordToken(credentials.getUsername(), credentials.getPassword()); + try { + subject.login(token); + } catch (AuthenticationException ae) { + ae.printStackTrace(); + attr.addFlashAttribute("error", "Invalid Credentials"); + return "redirect:/login"; + } + } + return "redirect:/home"; + } + + @GetMapping("/home") + public String getMeHome(Model model) { + + addUserAttributes(model); + + return "home"; + } + + @GetMapping("/admin") + public String adminOnly(Model model) { + addUserAttributes(model); + + Subject currentUser = SecurityUtils.getSubject(); + if (currentUser.hasRole("ADMIN")) { + model.addAttribute("adminContent", "only admin can view this"); + } + return "home"; + } + + @PostMapping("/logout") + public String logout() { + Subject subject = SecurityUtils.getSubject(); + subject.logout(); + return "redirect:/"; + } + + private void addUserAttributes(Model model) { + Subject currentUser = SecurityUtils.getSubject(); + String permission = ""; + + if (currentUser.hasRole("ADMIN")) { + model.addAttribute("role", "ADMIN"); + } else if (currentUser.hasRole("USER")) { + model.addAttribute("role", "USER"); + } + + if (currentUser.isPermitted("READ")) { + permission = permission + " READ"; + } + + if (currentUser.isPermitted("WRITE")) { + permission = permission + " WRITE"; + } + model.addAttribute("username", currentUser.getPrincipal()); + model.addAttribute("permission", permission); + } + +} diff --git a/java-security/apache-shiro/src/main/java/com/baeldung/shiro/models/UserCredentials.java b/java-security/apache-shiro/src/main/java/com/baeldung/shiro/models/UserCredentials.java new file mode 100644 index 0000000000..5dbafa30ec --- /dev/null +++ b/java-security/apache-shiro/src/main/java/com/baeldung/shiro/models/UserCredentials.java @@ -0,0 +1,28 @@ +package com.baeldung.shiro.models; + +public class UserCredentials { + + private String username; + private String password; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public String toString() { + return "username = " + getUsername(); + } +} diff --git a/java-security/apache-shiro/src/main/resources/application.yml b/java-security/apache-shiro/src/main/resources/application.yml new file mode 100644 index 0000000000..509f655919 --- /dev/null +++ b/java-security/apache-shiro/src/main/resources/application.yml @@ -0,0 +1,16 @@ +server: + port: 8081 + +logging: + level: + root: WARN + org.springframework.web: INFO + +shiro: + loginUrl: /login + successUrl: /home + unauthorizedUrl: /login + +spring: + freemarker: + suffix: .ftl \ No newline at end of file diff --git a/java-security/apache-shiro/src/main/resources/templates/home.ftl b/java-security/apache-shiro/src/main/resources/templates/home.ftl new file mode 100644 index 0000000000..37eb3d1812 --- /dev/null +++ b/java-security/apache-shiro/src/main/resources/templates/home.ftl @@ -0,0 +1,19 @@ + + + Home Page + + +

Welcome ${username}!

+

Role: ${role}

+

Permissions

+

${permission}

+Admin only +<#if adminContent??> + ${adminContent} + +
+
+ +
+ + \ No newline at end of file diff --git a/java-security/apache-shiro/src/main/resources/templates/index.ftl b/java-security/apache-shiro/src/main/resources/templates/index.ftl new file mode 100644 index 0000000000..0210d656fc --- /dev/null +++ b/java-security/apache-shiro/src/main/resources/templates/index.ftl @@ -0,0 +1,10 @@ + + + Index + + +

Welcome Guest!

+
+ Login + + \ No newline at end of file diff --git a/java-security/apache-shiro/src/main/resources/templates/login.ftl b/java-security/apache-shiro/src/main/resources/templates/login.ftl new file mode 100644 index 0000000000..7340f47204 --- /dev/null +++ b/java-security/apache-shiro/src/main/resources/templates/login.ftl @@ -0,0 +1,25 @@ + + + Login + + +

Login

+
+
+ <#if (error?length > 0)??> +

${error}

+ <#else> + + + +
+ +

+ +
+ +

+ +
+ + \ No newline at end of file diff --git a/java-security/apache-shiro/src/test/java/com/baeldung/shiro/SpringContextTest.java b/java-security/apache-shiro/src/test/java/com/baeldung/shiro/SpringContextTest.java new file mode 100644 index 0000000000..0b5e690403 --- /dev/null +++ b/java-security/apache-shiro/src/test/java/com/baeldung/shiro/SpringContextTest.java @@ -0,0 +1,18 @@ +package com.baeldung.shiro; + + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = { ShiroApplication.class }) +public class SpringContextTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + + } + +} \ No newline at end of file diff --git a/java-security/pom.xml b/java-security/pom.xml new file mode 100644 index 0000000000..f6e0df3990 --- /dev/null +++ b/java-security/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + java-security + 1.0-SNAPSHOT + java-security + pom + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + apache-shiro + spring-security + + + diff --git a/java-security/spring-security/.gitignore b/java-security/spring-security/.gitignore new file mode 100644 index 0000000000..020cda4898 --- /dev/null +++ b/java-security/spring-security/.gitignore @@ -0,0 +1,4 @@ + +/.idea/ +/target/ +/apache-shiro.iml \ No newline at end of file diff --git a/java-security/spring-security/pom.xml b/java-security/spring-security/pom.xml new file mode 100644 index 0000000000..a2c7430426 --- /dev/null +++ b/java-security/spring-security/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + spring-security + spring-security + + + com.baeldung + java-security + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + org.springframework.boot + spring-boot-starter-security + + + + diff --git a/java-security/spring-security/src/main/java/com/baeldung/springsecurity/Application.java b/java-security/spring-security/src/main/java/com/baeldung/springsecurity/Application.java new file mode 100644 index 0000000000..318a9a52ec --- /dev/null +++ b/java-security/spring-security/src/main/java/com/baeldung/springsecurity/Application.java @@ -0,0 +1,12 @@ +package com.baeldung.springsecurity; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} \ No newline at end of file diff --git a/java-security/spring-security/src/main/java/com/baeldung/springsecurity/config/SecurityConfig.java b/java-security/spring-security/src/main/java/com/baeldung/springsecurity/config/SecurityConfig.java new file mode 100644 index 0000000000..0516c1fddb --- /dev/null +++ b/java-security/spring-security/src/main/java/com/baeldung/springsecurity/config/SecurityConfig.java @@ -0,0 +1,45 @@ +package com.baeldung.springsecurity.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests(authorize -> authorize.antMatchers("/index", "/login") + .permitAll() + .antMatchers("/home", "/logout") + .authenticated() + .antMatchers("/admin/**") + .hasRole("ADMIN")) + .formLogin(formLogin -> formLogin.loginPage("/login") + .failureUrl("/login-error")); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.inMemoryAuthentication() + .withUser("Jerry") + .password(passwordEncoder().encode("password")) + .authorities("READ", "WRITE") + .roles("ADMIN") + .and() + .withUser("Tom") + .password(passwordEncoder().encode("password")) + .authorities("READ") + .roles("USER"); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + +} diff --git a/java-security/spring-security/src/main/java/com/baeldung/springsecurity/web/SpringController.java b/java-security/spring-security/src/main/java/com/baeldung/springsecurity/web/SpringController.java new file mode 100644 index 0000000000..d5eafaf954 --- /dev/null +++ b/java-security/spring-security/src/main/java/com/baeldung/springsecurity/web/SpringController.java @@ -0,0 +1,79 @@ +package com.baeldung.springsecurity.web; + +import java.util.Collection; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class SpringController { + + @GetMapping("/") + public String index() { + return "index"; + } + + @GetMapping("/login") + public String showLoginPage() { + return "login"; + } + + @RequestMapping("/login-error") + public String loginError(Model model) { + model.addAttribute("error", "Invalid Credentials"); + return "login"; + } + + @PostMapping("/login") + public String doLogin(HttpServletRequest req) { + return "redirect:/home"; + } + + @GetMapping("/home") + public String showHomePage(HttpServletRequest req, Model model) { + addUserAttributes(model); + return "home"; + } + + @GetMapping("/admin") + public String adminOnly(HttpServletRequest req, Model model) { + addUserAttributes(model); + model.addAttribute("adminContent", "only admin can view this"); + return "home"; + } + + private void addUserAttributes(Model model) { + Authentication auth = SecurityContextHolder.getContext() + .getAuthentication(); + if (auth != null && !auth.getClass() + .equals(AnonymousAuthenticationToken.class)) { + User user = (User) auth.getPrincipal(); + model.addAttribute("username", user.getUsername()); + + Collection authorities = user.getAuthorities(); + + for (GrantedAuthority authority : authorities) { + if (authority.getAuthority() + .contains("USER")) { + model.addAttribute("role", "USER"); + model.addAttribute("permissions", "READ"); + } else if (authority.getAuthority() + .contains("ADMIN")) { + model.addAttribute("role", "ADMIN"); + model.addAttribute("permissions", "READ WRITE"); + } + } + } + } + +} diff --git a/java-security/spring-security/src/main/resources/application.yml b/java-security/spring-security/src/main/resources/application.yml new file mode 100644 index 0000000000..d2cbd10a91 --- /dev/null +++ b/java-security/spring-security/src/main/resources/application.yml @@ -0,0 +1,12 @@ +server: + port: 8080 + +logging: + level: + root: WARN + org.springframework.web: INFO + org.springframework.security: INFO + +spring: + freemarker: + suffix: .ftl diff --git a/java-security/spring-security/src/main/resources/templates/home.ftl b/java-security/spring-security/src/main/resources/templates/home.ftl new file mode 100644 index 0000000000..dcf6d96d50 --- /dev/null +++ b/java-security/spring-security/src/main/resources/templates/home.ftl @@ -0,0 +1,20 @@ + + + Home Page + + +

Welcome ${username}!

+

Role: ${role}

+

Permissions

+

${permissions}

+Admin only +<#if adminContent??> + ${adminContent} + +
+
+ + +
+ + \ No newline at end of file diff --git a/java-security/spring-security/src/main/resources/templates/index.ftl b/java-security/spring-security/src/main/resources/templates/index.ftl new file mode 100644 index 0000000000..8f35c0af1b --- /dev/null +++ b/java-security/spring-security/src/main/resources/templates/index.ftl @@ -0,0 +1,10 @@ + + + Index + + +

Welcome Guest!

+
+ Go to the secured page + + \ No newline at end of file diff --git a/java-security/spring-security/src/main/resources/templates/login.ftl b/java-security/spring-security/src/main/resources/templates/login.ftl new file mode 100644 index 0000000000..266b5dfb80 --- /dev/null +++ b/java-security/spring-security/src/main/resources/templates/login.ftl @@ -0,0 +1,26 @@ + + + Login + + +

Login

+
+
+ <#if (error?length > 0)??> +

${error}

+ <#else> + + + +
+ +

+ +
+ +

+ + +
+ + \ No newline at end of file diff --git a/java-security/spring-security/src/test/java/com/baeldung/springsecurity/SpringContextTest.java b/java-security/spring-security/src/test/java/com/baeldung/springsecurity/SpringContextTest.java new file mode 100644 index 0000000000..a3adfa30c4 --- /dev/null +++ b/java-security/spring-security/src/test/java/com/baeldung/springsecurity/SpringContextTest.java @@ -0,0 +1,17 @@ +package com.baeldung.springsecurity; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = { Application.class }) +public class SpringContextTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + + } + +} \ No newline at end of file