sec:authorize and sec:authentication annotations don't work - spring-mvc

I have a Spring + Thymeleaf project with the following view code.
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring3-3.dtd">
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Contacts</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<div id="content">
<h1>Welcome to the site!</h1>
<p th:if="${loginError}">Wrong user or password</p>
<form th:action="#{/j_spring_security_check}" method="post">
<label for="j_username">Email address</label>:
<input type="text" id="j_username" name="j_username"/> <br/>
<label for="j_password">Password</label>:
<input type="password" id="j_password" name="j_password"/> <br/>
<input type="submit" value="Log in"/>
</form>
</div>
<div sec:authorize="isAuthenticated()">
User: <span sec:authentication="name">miquel</span>
</div>
</body>
</html>
The sec:authorize and sec:authentication attributes don't work as expected - the div is always shown, even if no user is logged in, and the span always reads "miquel".
Follows a relevant snippet from my controller class.
#RequestMapping(value = "/welcome.html")
public String wellcome() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
System.out.println("username: " + auth.getName());
return "home";
}
The println statement works as expected - if no user is logged in, it prints "anonymousUser", otherwise the username.
What am I doing wrong?

After comparing my application closely to the Thymeleaf & Spring Security demo applicaiton, I discovered the source of the error.
Apparently, in order for Thymeleaf to process the sec:authorize and sec:authentication attributes, you need to register SpringSecurityDialect as an additional dialect of the template engine bean.
<bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
<property name="additionalDialects">
<set>
<bean class="org.thymeleaf.extras.springsecurity3.dialect.SpringSecurityDialect" />
</set>
</property>
</bean>
This is surprising as there is no mention of that fact on the related Thymeleaf documentation page. I hope this helps others who will face the same issue in future.

In Spring Boot I just had to add the following dependency:
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>

For the java config version, it worked for me too by adding the spring security dialect:
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.addDialect(new TilesDialect());
templateEngine.addDialect(new SpringSecurityDialect());
return templateEngine;
}

Also, you may wish to clear the template cache after an authentication event, so your template is re-processed with new authentication data. Or, set the templates which are sensitive to a login session to non-cached (this is what I did), using ServletContextTemplateResolver.setNonCacheablePatterns().

Related

Spring MVC Redirect with POST

I am trying to redirect a user to external url to complete the transaction and this website is based SAML based authentication and accepts SAMLResponse as a post parameter. Below is my controller able to get the values in the logs
----- Controller ---------------------------------------------------
#RequestMapping(value="/redirect", method = { RequestMethod.GET, RequestMethod.POST })
public String redirect(HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirectAttrs) {
String samlRes = String.valueOf(request.getSession().getAttribute("STRRESPONSE"));
byte[] base64samlRes = Base64.encode(samlRes.getBytes());
redirectAttrs.addAttribute("SAMLResponse", base64samlRes);
L.debug("Redirecting " + samlRes);
L.debug("Redirecting Base64 Encoder " + new String(base64samlRes, Charset.forName("UTF-8")));
return "redirect";
---------------- Controller Ends ----------------------
and using the below html to post the external website.. I am seeing the browser the html title but it is not loading the external portal and values in the html is also null
---- HTML auto submit -----------------------
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Redirect Payment Portal</title>
</head>
<body>
<ul>
<li>SamlResponse: "${SAMLResponse}"</li>
</ul>
<form name="myRedirectForm" action="<external url>" method="post">
<input name="SAMLResponse" type="hidden" value="${SAMLResponse}" />
<noscript>
<input type="submit" value="Click here to continue" />
</noscript>
</form>
<script type="text/javascript">
$(document).ready(function() {
document.myRedirectForm.submit();
});
</script>
</body>
</html>
===================== End HTML ----------------------
Am i missing anything
I am able to retrieve the value in html by modifying the value [[${SAMLResponse}]] but the form is not getting submitted
Finally issue is resolved with the following updates
------ HTML---
modified the following line
<input name="SAMLResponse" type="hidden" value="${SAMLResponse}" />
to
<input name="SAMLResponse" type="hidden" th:value="${SAMLResponse}" />
--- End HTML ----
----- Controller Changes ----
#RequestMapping(value="/redirect", method = { RequestMethod.GET, RequestMethod.POST })
public ModelAndView redirect(HttpServletRequest request, HttpServletResponse response, Model model) {
String samlRes = String.valueOf(request.getSession().getAttribute("STRRESPONSE"));
byte[] base64samlRes = Base64.encode(samlRes.getBytes());
model.addAttribute("SAMLResponse", new String(base64samlRes, Charset.forName("UTF-8"));
L.debug("Redirecting " + samlRes);
L.debug("Redirecting Base64 Encoder " + new String(base64samlRes, Charset.forName("UTF-8")));
return new ModelAndView ("redirect");
---- Controller Changes End ------

Unable to serve static resources with spring, receive index instead

I have a simple Spring web application.
#Controller
public class GreetingController {
#Autowired
GreetingRepository repository;
#GetMapping("/greeting")
public String greetingForm(Model model) {
model.addAttribute("greeting", new Greeting());
return "greeting";
}
#PostMapping("/greeting")
public String greetingSubmit(#ModelAttribute Greeting greeting) {
repository.save(greeting);
return "result";
}
}
The HTML is:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Greeting Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" th:href="#{/css/style.css}"/>
</head>
<body>
<h1>Form</h1>
<form action="#" th:action="#{/greeting}" th:object="${greeting}" method="post">
<p>Id: <input type="text" th:field="*{id}" /></p>
<p>Message: <input type="text" th:field="*{content}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
This is the css file that is referenced in the HTML:
p {
color: #ff5588;
}
However, the css is not applied.
In fact, when I query localhost:8080/css/style.css it returns the HTML content of the index page.
It might be a security configuration issue. Is there a security implementation (SpringSecurity or custom) on your project? If so, does your user have access to /css/* url or this url has public access? The redirection might be occur if user doesn't have access to url or there is an exception while processing request.
The security configuration turned out to be blocking all requests to resources. In stead, it was redirecting those requests to the index page (which was configured).
The solution turned out to be simple, authorize all requests to the resources of the website (/images/** and /css/** and /js/**).
Once that was configured, the web-application worked as expected.

Error while moving HTML form from jsp to ThymeLeaf

I am trying to follow this as reference Serving Static content in SpringBoot
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.ui.Model;
/**
* Created by Eric on 11/25/2015.
*/
#org.springframework.stereotype.Controller
public class Controller {
#RequestMapping("/appPage")
public String greeting(#RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
model.addAttribute("title", "Best Of the App");
model.addAttribute("basecontext", "Best Of the App");
return "appPage";
}
}
My HTML form being below
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${title}" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'Hello, ' + ${name} + '!'" />
<input type="hidden" type="text" id="basecontext" value='${basecontext}'/>
</body>
</html>
I am trying to set value in hidden input field. But that gives me error
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: Exception parsing document: template="appPage", line 9 - column 33
I am trying to move this html page which was getting loaded in a JSP application to Spring Boot + ThymeLeaf.
If I simply place this content in index.html without a Context handler in Controller. the page is loaded just fine. Thymeleaf does not throw any error.
ThymeLeaf uses xml and not html and you are not allowed to have attributes of the same name in xml type="hidden" type="text"
You actually should get SAXParseException: Attribute "type" was already specified for element in your spring log

The remote server returned an error: (405) Method Not Allowed. c#

So I am working in a project to send data from a C# application to ASP web application; the problem is when I want to send the data I get this error :The remote server returned an error: (405) Method Not Allowed. Here is my C# code:
static void Main(string[] args)
{
using (var wb = new WebClient())
{
var data = new NameValueCollection();
string url = "http://localhost:4241/HtmlPage2.html";
data["Text1"] = "Anas";
data["Text2"] = "Anas";
var response = wb.UploadValues(url, "POST", data);
}
}
and here my ASP code (it's just a HTML page for testing, the code is implemented in HtmlPage2.html and when I submit the button it passes the data to HtmlPage2.html)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<form method="Post" action="HtmlPage2.html">
<input id="Text1" type="text" name="Text1" />
<input id="Text2" type="text" name="Text2" />
<input id="Button1" type="submit" value="button" />
</form>
</body>
</html>
NB:My IIS is already enabled :)
So if someone can help me I will be very appreciative :)
A HTML file is a static file on a filesystem-based webserver, there is no way for it to handle POST requests, only GET (unless you're using WebDAV, but that's another story).
Basically the <form action="HtmlPage2.html"> fragment is incorrect. If it does work in your webbrowser then check the DOM of the page to see if the action attribute is being changed.

Spring MVC Static Resources partially work

I have a basic directory app that works fine except that it seems to only sometimes find the static resources that I’ve configured using the mvc:resources tag. My search of the board found problems related to handler mappings, but my problem seems to be different.
Specifically, when the PersonController is called via a method mapping to “/person”, it returns personlist.jsp using the view resolver and correctly finds and uses the static css and js files. No problems.
When the same controller is called via another method mapping to “/person/{familyid}” ( narrows the person list to a particular family), it returns the same personlist.jsp…but now it fails to find or use the css and js files (though it does display the correct data).
I don’t understand why there is a behavior difference since both scenarios use the same Controller, the same return String (return “personlist”), and resolve to the same JSP (ie. with the same Head section links for the css, js).
I looked at what came back in the browser for each case using ‘view source’, and both pages return the same head tag rendering for the css and js linking:
<link href="resources/css/directory.css" rel="stylesheet" type="text/css"></link>
<script type="text/javascript" src="resources/scripts/jquery-1.7.min.js"></script>
<script type="text/javascript" src="resources/scripts/directory.js"></script>
I thought the problem could be with my tag mapping, so I also tried this:
<resources mapping="**/resources/**" and
resources mapping="resources/**"
but no help.
Am I approaching the use of static resources properly here (and what is the right resources tag mapping if that’s the problem)? Thanks.
I am using Spring 3.0.6 and my css and js files are located under /WebContent/resources/css and /WebContent/resources/scripts respectively, which are mapped using the mvc:resource tag (see below).
PersonController:
#Controller
public class PersonController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
List<Person> personList;
Boolean familyCalled = false;
#Autowired
PersonService personService;
#RequestMapping(value="/people", method=RequestMethod.GET)
public String people(Model model) {
logger.debug("Received request to show peoplelist page");
System.out.println("Running inside people() method of PersonController");
personList = personService.getPersons();
familyCalled = false;
model.addAttribute("personList", personList);
return "personlist";
}
#RequestMapping(value="/people/{familyId}", method=RequestMethod.GET)
public String familyMembers(#PathVariable("familyId") String fid, Model model) {
System.out.println("Running inside familyMembers() method of PersonController");
personList = personService.getPersonsInFamily(fid);
familyCalled = true;
model.addAttribute("personList", personList);
return "personlist";
}
Servlet-Context.xml (without namespaces):
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- for transactions -->
<tx:annotation-driven/>
<!-- Needed for #PreAuthorize security on methods -->
<aop:aspectj-autoproxy/>
<context:annotation-config />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="resources/" />
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven/>
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.c3works.preps" />
</beans:beans>
personlist.jsp (Head section):
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
</meta>
<title>XXXXXXXXXXXXXXXXXXX</title>
<link href="resources/css/directory.css" rel="stylesheet" type="text/css">
</link>
<script type="text/javascript" src="resources/scripts/jquery-1.7.min.js">
</script>
<script type="text/javascript" src="resources/scripts/directory.js">
</script>
</head>
Your URLs are relative and therefore the browser is looking for the resources in the wrong place. (Check the resulting HTML code)
One solution is to use the <spring:url> tag to build the urls of the resources.
<spring:url var="banner" value="/resources/images/banner-graphic.png" />
<img src="${banner}" />

Resources