Authentication issue while trying to connect to mongo on Docker from Spring data mongodb - spring-mvc

I have a mongo instance running on docker container. I am trying to connect to it from a spring mvc application using xml configuration.
<mongo:mongo-client id="mongoClient" host="hname" port="27017" credential="user:pwd#dbname"/>
<mongo:db-factory id="mongoDbFactory" dbname="dbname" mongo-client-ref="mongoClient" />
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongoClient"/>
<constructor-arg name="databaseName" value="dbname"/>
</bean>
<mongo:repositories base-package="xxx.yyy.zzz.core.repository" mongo-template-ref="mongoTemplate" />
When I run the container I see an error saying:
Error! Query failed with error code 13 with name 'Unauthorized' and error message 'not authorized on dbname to execute command { find: "attributes", filter: { unique_user_id: "iTrustUIN" }, limit: 2, $db: "dbname", lsid: { id: UUID("bc5daa8c-8fc7-44da-8b8c-0fa91384cbd8") } }' on server dbname:27017;}}
what am I doing wrong here? Thank you in advance.
Note: I have couple of springboot applications and I can successfully connect to the mongo from those.
My pom.xml
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-core</artifactId>
<version>4.6.0</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.6.0</version>
</dependency>
thanks,
Pbale

Finally, I could able to make it work.
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.7.1</version>
</dependency>
applicationConetext.xml:
<mongo:db-factory id="mongoDbFactory" connection-string="mongodb://user:pwd#host:27017/dbname"/>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongoDbFactory" />
</bean>
<mongo:repositories
base-package="edu.illinois.sample.spring.data" mongo-template-ref="mongoTemplate"/>
<bean id="attrImpl" class="edu.illinois.sample.spring.data.AttributesDaoImpl"/>
java code:
try (FileSystemXmlApplicationContext actx = new FileSystemXmlApplicationContext(springConfig)) {
AttributesDaoImpl attrImpl = actx.getBean(AttributesDaoImpl.class);
try {
Attributes attr = attrImpl.getAttributesByUniqueUserId("iTrustUIN");
} catch(Exception e) {
}

Related

Spring Security 6 and JSP view rendering

I'm upgrading an application from Spring Boot 2.7 to Spring Boot 3 which includes updating to Spring Security 6.
We have the following properties set:
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp
We use JSPs as a template language, where the controller returns the view file name e.g.
#RequestMapping("/")
public String home() {
return "home";
}
This will render the JSP page /WEB-INF/view/home.jsp
The security config is e.g.
#Configuration
public class SecurityConfig {
#Bean
public SecurityFilterChain config(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((auth) -> auth
.requestMatchers("/").permitAll()
.anyRequest().authenticated()
);
}
Since upgrading, visiting localhost/ redirects the browser to localhost/WEB-INF/view/home.jsp and this returns a 403 because access to that page isn't permitted.
If I allow access to this with .requestMatchers("/", "/WEB-INF/**").permitAll() it works OK (i.e. stays on / and renders the JSP page) but this seems like a bad idea, and an unnecessary step.
With debug logging on, Spring logs the following:
DEBUG [requestURL=/] o.s.security.web.FilterChainProxy : Securing GET /
DEBUG [requestURL=/] o.s.security.web.FilterChainProxy : Secured GET /
DEBUG [requestURL=/] o.s.security.web.FilterChainProxy : Securing GET /WEB-INF/view/home.jsp
DEBUG [requestURL=/] o.s.security.web.FilterChainProxy : Secured GET /WEB-INF/view/home.jsp
I cant' see anything in Spring Security migration guide about this, does anyone know what is going on?
Update
I've isolated this into a clean example:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>jsptest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jsptest</name>
<packaging>war</packaging>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Application.java
#SpringBootApplication
#Controller
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public SecurityFilterChain config(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((auth) -> auth
.requestMatchers("/", "/WEB-INF/view/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
#RequestMapping("/")
public String home() {
return "home";
}
}
src/main/resources/application.properties:
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp
src/main/webapp/WEB-INF/view/home.jsp:
hello
Something I've overlooked first as well.
In spring security 6, forwards and includes are part of the security filter by default.
See https://docs.spring.io/spring-security/reference/5.8.0/migration/servlet/authorization.html#_permit_forward_when_using_spring_mvc
Allowing forwards globally can be done through this additional line in security configuration.
.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()

Controller class is not getting provoked in Spring MVC

Spring MVC Controller class is not working and throwing 404.
In application I created an entity and added all the credentials of my MS-SQL database. However, after staring the app and hitting the submit button the app is landed to 404 and controller is not provoked and entity is not created as well.
index.jsp is as follows:
<form action = "/save" method = "post">
ID: <input type = "text" name = "uid">
<br />
Name: <input type = "text" name = "name" />
<input type = "submit" value = "Submit" />
</form>
Controller class is as follows:
#Controller
public class MyController {
#Autowired
public EmployeeDao empDao;
#RequestMapping("/save")
#ResponseBody
public String save(Employee emp){
System.out.println("Here");
empDao.saveEmployee(emp);
return "success";
}
}
The Entity Class:
Entity
#Table(name="employee")
public class Employee {
#Id
private int uid;
private String name;
}
The context class:
#Bean
public DriverManagerDataSource getDataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
ds.setUrl("jdbc:sqlserver://localhost:1433;databasename=cruddb11;integratedsecurity=true");
ds.setUsername("ABCD");
ds.setPassword("00000");
return ds;
}
The Pom:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.websparrow</groupId>
<artifactId>spring-mvc-fetch-data</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- Hibernate Core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.17.Final</version>
</dependency>
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.0.Alpha5</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.0.2.Final</version>
</dependency>
<!-- spring mvc dependency -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- spring jdbc dependency -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.2.2.jre8</version>
</dependency>
<!-- mysql databse connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>
This will not work as you expect.
1.) This is not neccessary but helpful if you have more than one leading part in your url. Annotate your class with the #RequestMapping Annotation. Like this:
#RequestMapping(value="/fileoperations") // Then you don't need the leading slash in the method
#Scope(value="session")
Use the second line if you are using sessions e.g. with Tomcat.
2.) The form only contains the variables uid and name so you must query them as parameters to work with in your controller.
3.) And also you must tell your controller to use the right Requestmethod. Like this:
#RequestMapping(value="save", method=RequestMethod.POST)
public #ResponseBody String save(
#RequestParam String uid,
#RequestParam String name) {
System.out.println("Here");
// Maybe you should load the Employee first before updating it.
Employee emp = this.empDao.readEmployee(name);
if (emp != null) {
emp.setUID(uid);
emp.setName(name);
this.empDao.saveEmployee(emp);
return "success";
} else {
return "error: no employee here by that name";
}
}
Change your save method signature to following, annotating Employee parameter with #ModelAttribute
#Autowired
public EmployeeDao empDao;
#RequestMapping("/save")
#ResponseBody
public String save(#ModelAttribute Employee emp){
System.out.println("Here");
empDao.saveEmployee(emp);
return "success";
}
You had better change #RequestMapping to #Post.

hibernate Validator not validating model class

This question has been asked a lot of times, even after going through all the solutions i wansn't able to get hibernate validator working.
Controller class:-
#RequestMapping(value={"/setReg"},method={RequestMethod.GET,RequestMethod.POST})
public ModelAndView setRegistration( #Valid #ModelAttribute("userDetails") UserDetails userDetails,BindingResult bindingResult){
logger.info("setRegistration :Entry");
if(bindingResult.hasErrors()){
logger.info("binding success");
logger.info(userDetails.getUser_first_name());
logger.info("validation not working");
}
else{
logger.info("binding failure");
}
logger.info("setRegistration :Exit");
return null;
}
servlet-context:-
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<context:component-scan base-package="com.xmith.services"/>
<context:component-scan base-package="com.xmith.dao"/>
<context:component-scan base-package="com.xmith.models"/>
<context:component-scan base-package="com.xmith.sweb" />
<context:annotation-config/>
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- 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>
dependency:-
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
validation class:-
public class UserDetails {
private String user_id;
#Size(min=3,max=7,message="user first name must have max length 7")
private String user_first_name;
private String user_last_name;
private String user_age;
private String user_email;
private String user_password;
Note:-
in above code i am trying to validate "user_first_name"(min=3,max=7,message="user first name must have max length 7"), however when i enter input more than 7 it still sets "user_first_name".
output:---
17:33:12.399 [http-bio-8080-exec-1] DEBUG org.hibernate.validator.resourceloading.PlatformResourceBundleLocator - ValidationMessages not found.
17:33:12.401 [http-bio-8080-exec-1] DEBUG org.hibernate.validator.resourceloading.PlatformResourceBundleLocator - ContributorValidationMessages not found.
17:33:12.403 [http-bio-8080-exec-1] DEBUG org.hibernate.validator.resourceloading.PlatformResourceBundleLocator - org.hibernate.validator.ValidationMessages found.
17:33:12.417 [http-bio-8080-exec-1] INFO com.xmith.sweb.HomeController - setRegistration :Entry
17:33:12.418 [http-bio-8080-exec-1] INFO com.xmith.sweb.HomeController - binding success
17:33:12.418 [http-bio-8080-exec-1] INFO com.xmith.sweb.HomeController - qwertyuiiii
17:33:12.418 [http-bio-8080-exec-1] INFO com.xmith.sweb.HomeController - validation not working
17:33:12.418 [http-bio-8080-exec-1] INFO com.xmith.sweb.HomeController - setRegistration :Exit
What am i missing here?
my boolean logic was wrong as pointed by – JB Nizet

Spring EhCache configuration - Cannot find class [org.springframework.cache.ehcache.EhCacheManagerFactoryBean]

I need help with ehCache configuration.
These what i did :
ehcache.xml inside my src/main/resources folder
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true"
monitoring="autodetect"
dynamicConfig="true">
<diskStore path="java.io.tmpdir" />
<cache name="allNodesCache"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300" timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
<persistence strategy="localTempSwap" />
</cache>
ehCache configuration inside my applicationContext-web.xml
<!-- ehCache configuration -->
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
<!-- EhCache library setup -->
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="ehcache.xml"/>
pom.xml:
<!-- ehCache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.7.2</version>
</dependency>
My repository class:
#Repository
public interface NodeRepository extends JpaRepository {
#Cacheable(value = "allNodesCache", key = "#node")
#Query("select new com.datum.fnd.domain.Node(c.idNode, c.name, c.address, c.description, c.point) from Node c")
I got message like this :
Cannot find class [org.springframework.cache.ehcache.EhCacheManagerFactoryBean] for bean with name 'ehcache' defined in ServletContext resource [/WEB-INF/spring/applicationContext-web.xml]; nested exception is java.lang.ClassNotFoundException: org.springframework.cache.ehcache.EhCacheManagerFactoryBean
Add the spring context support dependency to your classpath:
https://mvnrepository.com/artifact/org.springframework/spring-context-support

How do I exclude certain service during development with Spring MVC

I have the following service which send email each time a purchase made by customer
#Component
public class EmailerService extends JavaMailSenderImpl {
public boolean sendEmail(String userFullName, String recipient, String subject, String content,String replyTo)
throws AddressException, MessagingException {
initJavaMailProps(replyTo);
Message message = new MimeMessage(getSession());
message.setFrom(new InternetAddress(senderEmailAddress));
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(recipient));
message.setSubject(subject);
if (withGreeting())
content = "Dear " + userFullName + ",\n\n"+content;
if (withRegards())
content += "\n\nBest Regards, \n\nDNA G2 Support";
message.setText(content);
Transport.send(message);
return true;
}
And on my XML configuration I have two Spring profile which is named "normal" and "cloud". Now I would like to add a new profile lets say "Development" and would like to "disable" this service during development. This is due to many emails are still being sent out during my local testing. What's the easiest way to achieve this ?
I assume you are talking about maven profiles when your refer to "normal" and "cloud".
1) add a property to your maven profile in pom.xml (notice that Development is false). For convenience the Development profile is the defaut profile also. If you need to run another profile you can do so via mvn package -P cloud.
<profiles>
...
<profile>
<id>normal</id>
<properties>
<profile.email.enabled>true</profile.email.enabled>
</properties>
</profile>
...
<profile>
<id>cloud</id>
<properties>
<profile.email.enabled>true</profile.email.enabled>
</properties>
</profile>
...
<profile>
<id>Development</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<profile.email.enabled>false</profile.email.enabled>
</properties>
</profile>
...
</profiles>
2) You need to enable resource filtering so your can inject this variable into your maven build. Here we are saying the all files in the /src/main/resources should be filtered with our maven properties.
<project>
...
...
<build>
...
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
...
</resources>
...
</build>
...
</project>
2)In one of your spring .property files (ie. environment.properties) add the following. Here we are saying that the property email.enabled will use whatever is included in the maven profile.
email.enabled=$(profile.email.enabled);
3) Now in your email service add the following instance variable, this will inject the property from your .property file into the variable emailEnabled
#Value("email.enabled")
private boolean emailEnabled;
4) Now you can do that check in the service
if (emailEnabled) {
...
}

Resources