Spring Boot doesn't load javascript file - spring

After Spring starts, I open my ajax.html page, but nothing happens. There is no error message, the js file just doesn't start. If I write javascript-code in ajax.html, it works normally.
ajax.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org" xmlns:c="http://xmlns.jcp.org/xml/ns/javaee">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script type="text/javascript"
src="webjars/jquery/2.2.4/jquery.min.js"></script>
<script type="text/javascript" src="../static/js/main.js"></script>
</head>
<body>
<div id="fill">
</div>
</body>
</html>
project structure
enter image description here

I had the same issue, and solved it in the following way:
I added the addResourceHandlers to my Java config file:
#Configuration
#EnableWebMvc
#ComponentScan
public class WebConfig implements WebMvcConfigurer {
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**", "/js/**")
.addResourceLocations("classpath:/static/css/", "classpath:/static/js/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
resources folder contains a static/js and a static/css folder both containing the specified files.
Hope it gives you help!

Have you added the resource handler for webjars? See: https://www.baeldung.com/maven-webjars
../static/js/main.js seems wrong. In spring boot, resources in the static directory are referred to without "static" in the URL, so just /js/main.js.
Other than that, are the scripts being loaded? What does the Network tab for the Console say?

As you are using Spring boot, you don't have to add "/static/**" folder in your url. You should miss "/static/" and write like this:
<script type="text/javascript" src="/js/main.js"></script>
And make sure that if you are using spring securiry, you should permit All to access "/js/**" path :
http
.csrf().disable()
.authorizeRequests()
.antMatchers( "/js/**", "/css/**")
.permitAll()
.anyRequest()
.authenticated();

Related

display spring security authentication object when SessionCreationPolicy.STATELESS

#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
MyUserDetailsService myUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/index").permitAll();
http.authorizeRequests().antMatchers("/main").permitAll();
http.formLogin().loginPage("/login").permitAll().successHandler(successHandler());
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // Session is STATELESS
}
I set spring security sessionpolicy to STATLESS
because I'm using JWT so that STATLESS would be better
but STATELESS cause one problem
it's impossible to dispaly authentication object in thymeleaf
<h1>[[${#authentication }]]</h1>
if I changed session policy I could display authentication object
but but that's not what i want
in short
can i use authentication object with thymeleaf when spring's session policy is STATELESS
Form based log in requires a session, so marking as stateless would mean that the user is not available. Likely you can see the page because it is marked as permitAll which means no user is necessary to see it.
To fix this, you can switch to a form of authentication that is stateless too (i.e. it is included in every request). For example:
// #formatter:off
http
.authorizeRequests()
.mvcMatchers("/index", "/main").permitAll()
.and()
.httpBasic()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// #formatter:on
I'm also not sure about the syntax the themleaf template is using. For me, I use something like this:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Test</title>
</head>
<body>
<h1 th:text="${authentication?.name}"></h1>
</body>
</html>
Then I use the following to expose the Authentication as a model attribute:
#Controller
public class IndexController {
#GetMapping("/")
String index() {
return "index";
}
#ModelAttribute
Authentication authentication(Authentication authentication) {
return authentication;
}
}
I have a test that validates it works
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class DemoApplicationTests {
#Autowired
TestRestTemplate rest;
#Test
void indexWhenAnonymous() throws Exception{
ResponseEntity<String> result = rest.exchange(RequestEntity.get(URI.create("/")).build(), String.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getBody()).doesNotContain("user");
}
#Test
void indexWhenAuthenticated() throws Exception{
ResponseEntity<String> result = rest.exchange(RequestEntity.get(URI.create("/")).headers(h -> h.setBasicAuth("user", "password")).build(), String.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getBody()).contains("user");
}
}
You can find the complete sample at https://github.com/rwinch/spring-security-sample/tree/display-auth-stateless-thymeleaf which allows log in with the username user and password password.

spring security tag library sec:authorize url not working

In my spring boot project, I use spring security tag libs.
When I logged in as user id which has ROLE_USER role, It supposed to not be shown ADMIN area according to my configuration below.
<sec:authorize url="/admin/**">
<p>This is shown who has a role ADMIN</p>
</sec:authorize>
this part.
but It's not working.
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%# taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>Welcome Home <sec:authentication property="name"/></h2>
<h3>roles : <sec:authentication property="principal.authorities"/></h2>
<sec:authorize access="hasRole('ADMIN')">
<p>This is shown who has a role ADMIN</p>
</sec:authorize>
<sec:authorize access="hasRole('USER')">
<p>This is shown who has a role USER</p>
</sec:authorize>
<sec:authorize access="hasRole('TESTER')">
<p>This is shown who has a role TESTER</p>
</sec:authorize>
<sec:authorize url="/admin/**">
<p>This is shown whom can access to /admin/**</p>
</sec:authorize>
<sec:authorize url="/user/**">
<p>This is shown whom can access to /user/**</p>
</sec:authorize>
<sec:authorize url="/tester/**">
<p>This is shown whom can access to /tester/**</p>
</sec:authorize>
<form action="/logout" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
[view][1]
I have tried all the answers in stackoverflow about this problem but I still can not fix this.
It has been over 2 weeks tried to fix this problem.
when I tested with thymeleaf same java configurations, It worked. but not working with jsp.
here is my settings
java spring security configuration
Please help me to fix this problem.
#Configuration
#EnableWebSecurity
public class WebSecurity {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.expressionHandler(expressionHandler())
.antMatchers("/", "/home", "/test").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("USER")
.antMatchers("/tester/**").hasAnyRole("TESTER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Bean
public RoleHierarchyImpl roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
String hierarchy ="ROLE_ADMIN > ROLE_USER and ROLE_USER > ROLE_TESTER";
roleHierarchy.setHierarchy(hierarchy);
return roleHierarchy;
}
// create two users, admin and user
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER")
.and()
.withUser("tester").password("{noop}tester").roles("TESTER")
.and()
.withUser("admin").password("{noop}admin").roles("ADMIN");
}
private SecurityExpressionHandler<FilterInvocation> expressionHandler() {
DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
return defaultWebSecurityExpressionHandler;
}
}
build.gradle
buildscript {
ext {
springBootVersion = '2.0.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.bulky'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
// tag::security[]
compile("org.springframework.boot:spring-boot-starter-security")
compile 'org.springframework.security:spring-security-taglibs:5.0.5.RELEASE'
// end::security[]
compile 'javax.servlet:jstl:1.2'
compile 'org.apache.tomcat.embed:tomcat-embed-jasper:9.0.0.M18'
}
ps: sorry for the poor english
All your security configs are correct except WebSecurity class which ins't extending WebSecurityConfigurerAdapter. I think you need to extend that class first to ensure you override the configure method:
#Configuration
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
//Your Code here
}

Spring Boot and Security Dynamic Authentication and Authorization

I am going to develop a login page using spring boot and security which users and roles can be created by admin so the system can have many roles and users...also admin can assign the roles to users and remove them as well.
I have used good samples of how to implement it but after reading so much doc and tutorials still having below questions and don't know what is the best practice to implement spring security and boot together.tried to move on debug mode to find out what is happening behind the scene step by step.
my assumption was for each and every http request application refers to WebSecurityConfig class to check the access but surprisingly it was not like that and fellow was as below.seems application goes to config class once at the beginning and every things populates.bootstrap doing so many actions in background and it made me confuse and can't understand the relation between the classes.
configureGlobal-->configure-->whatever you write as a URL it goes to /login) -->controller (login method) --> submit the form with user/pass --> loadUserByUsername --> controller (welcome method) --> welcome.jsp
1-what exactly configureGlobal and configure do when the application loads?
2-what is the exact role of AuthenticationManagerBuilder?
3-how spring security knows to send the user/pass after form submition to loadUserByUsername method?
4-loadUserByUsername return user object to where? because when methods reach to the end it redirects to controller welcome method and it send you to welcome method when username and password is correct.
4-how to use grantedAuthorities to re-direct the user based on his role to different pages?
<%# taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="">
<meta name="author" content="">
<title>Log in with your account</title>
<link href="${contextPath}/resources/css/bootstrap.min.css" rel="stylesheet">
<link href="${contextPath}/resources/css/common.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<form method="POST" action="${contextPath}/login" class="form-signin">
<h2 class="form-heading">Log in</h2>
<div class="form-group ${error != null ? 'has-error' : ''}">
<span>${message}</span>
<input name="username" type="text" class="form-control" placeholder="Username"
autofocus="true"/>
<input name="password" type="password" class="form-control" placeholder="Password"/>
<span>${error}</span>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<button class="btn btn-lg btn-primary btn-block" type="submit">Log In</button>
<h4 class="text-center">Create an account</h4>
</div>
</form>
</div>
<!-- /container -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="${contextPath}/resources/js/bootstrap.min.js"></script>
</body>
</html>
WebSecurityConfig Class
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/registration").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
UserDetailsServiceImpl class
#Service
public class UserDetailsServiceImpl implements UserDetailsService{
#Autowired
private UserRepository userRepository;
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
for (Role role : user.getRoles()){
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
}
UserController Class
#Controller
public class UserController {
#Autowired
private UserService userService;
#Autowired
private SecurityService securityService;
#Autowired
private UserValidator userValidator;
#RequestMapping(value = "/registration", method = RequestMethod.GET)
public String registration(Model model) {
model.addAttribute("userForm", new User());
return "registration";
}
#RequestMapping(value = "/registration", method = RequestMethod.POST)
public String registration(#ModelAttribute("userForm") User userForm, BindingResult bindingResult, Model model) {
userValidator.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "registration";
}
userService.save(userForm);
securityService.autologin(userForm.getUsername(), userForm.getPasswordConfirm());
return "redirect:/welcome";
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(Model model, String error, String logout) {
if (error != null)
model.addAttribute("error", "Your username and password is invalid.");
if (logout != null)
model.addAttribute("message", "You have been logged out successfully.");
return "login";
}
#RequestMapping(value = {"/", "/welcome"}, method = RequestMethod.GET)
public String welcome(Model model) {
return "welcome";
}
}
I would like to share the answer of some questions which are clear to me now.
when you start your project , first of all it goes to WebSecurityConfig class and look for configureGlobal method to build the authentication process and then looks for configure method to set the security.
AuthenticationManagerBuilder is a class with many methods like userDetailsService which is used to authenticate based on user details so when you login it will sends the credentails to a class which has implemented UserDetailsService interface.
A POST to the /login URL will attempt to authenticate the user so configureGlobal will do the needful.
It has called from configureGlobal method and is returned backed there and still everything is in root path so will find the proper method in controller class.
AuthenticationSuccessHandler can help in this regard.

Spring Boot and Thymeleaf Resource folder Issue

I am trying to set resource folder in my Spring Boot project. But not able to make it. Please help. I am trying to integrate thymeleaf.
I am able to get index.html
But I am not able to include resource /css/mobile-angular-ui-desktop.min.css file in index.html.
It give me 404 Page Not found error.
index.html
<!DOCTYPE html>
<html>
<head>
<title>Provision Admin</title>
<link rel="stylesheet" th:href="#{/css/mobile-angular-ui-base.min.css}"
href="../static/css/mobile-angular-ui-base.min.css" />
<link rel="stylesheet"
href="/css/mobile-angular-ui-desktop.min.css" />
<script type="text/javascript">
var appContext = '/profilebatch';
</script>
</head>
<body>
</body>
</html>
I setting following security.
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class ApplicationSecurity extends
WebSecurityConfigurerAdapter {
#Autowired
private SecurityProperties security;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/css/**")
.permitAll().antMatchers("**/favicon.ico").permitAll()
.antMatchers("/secure/**").fullyAuthenticated().and()
.formLogin().loginPage("/login").failureUrl("/login?error")
.permitAll().and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
}
#Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("user").password("user")
.roles("USER").and().withUser("admin").password("admin")
.roles("ADMIN");
}
}
Finally things are working fine.
I removed #EnableWebMvc in my configuartion.
you don't have th:href for desktop, if you can access base so this is your problem:
th:href="#{/css/mobile-angular-ui-desktop.min.css}"
Static resources default place at /public instead of /src/main/resources/static

Spring security http basic auth for Rest api with Java config

I am trying to secure a CXF based rest API with Spring security. While my configuration technically works, I cannot seem to get the API to respond with JSON rather than an HTML message upon 401. Based on a few other SO posts I put together the following java config, using groovy, for the spring security configuration:
#Configuration
#EnableWebSecurity
#Slf4j
class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) {
http.antMatcher('/api/**')
.authorizeRequests()
.antMatchers('/api/admin/**').hasRole('ADMIN')
.antMatchers('/api/**').hasRole('USER')
.and()
.httpBasic()
.and()
.addFilterBefore(
new BasicAuthenticationFilter(authenticationManager: authenticationManager(), authenticationEntryPoint: new BasicJsonEntryPoint(realmName: 'Local')),
BasicAuthenticationFilter.class
)
}
static class BasicJsonEntryPoint extends BasicAuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest req, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
log.debug 'Handling response'
response.addHeader HttpHeaders.WWW_AUTHENTICATE, /Basic realm="${getRealmName()}"/
response.setStatus HttpStatus.UNAUTHORIZED.value()
response.getWriter().println([status: HttpStatus.UNAUTHORIZED.value(), message: e.getMessage()].toJson())
}
}
}
I've tried numerous variations on this general approach, but no matter what I get HTML back from the API. See the following req/resp:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>Error 401 Full authentication is required to access this resource</title>
</head>
<body>
<h2>HTTP ERROR 401</h2>
<p>Problem accessing /api/test. Reason:
<pre> Full authentication is required to access this resource</pre>
</p>
<hr />
<i>
<small>Powered by Jetty://</small>
</i>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
</body>
</html>
I'm just guessing here, but Jetty is a little too helpful sometimes when your application emits http response codes other than 200s. My recommendation is that you add some logic to your web.xml to short circuit Jetty's helpfulness. The full technique that got my application out of a similar issue is documented on: How do I suppress Jetty 8's default ErrorHandler?
Good luck.

Resources