I'm trying to follow this example about Spring Security and adapt it to my needs but I'm having troubles with its configuration
I have a LoginService that looks like this:
// This example does not make sense of course but I'm just
// trying to make it work with #PreAuthorize("hasRole('ROLE_ADMIN')")
// and see an exception or something that lets me know that
// it is actually working ..
public class LoginService {
private final static Logger LOGGER = Logger.getLogger(LoginService.class.getName());
private AdministratorRepository administratorRepository;
public LoginService(DSLContext ctx) {
this.administratorRepository = new AdministratorRepository(ctx);
}
#Transactional
#PreAuthorize("hasRole('ROLE_ADMIN')")
public void login(String userId, String password) {
LOGGER.debug("Login for " + userId);
this.administratorRepository.login(userId, password);
}
}
and I am already initalizing this class in my applicationContext-jooq.xml like this:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/mz_db" />
<property name="username" value="postgres" />
<property name="password" value="1234" />
</bean>
<!-- Configure Spring's transaction manager to use a DataSource -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Configure jOOQ's TransactionProvider as a proxy to Spring's transaction manager -->
<bean id="transactionProvider"
class="com.mz.server.web.SpringTransactionProvider">
</bean>
<!-- Configure jOOQ's ConnectionProvider to use Spring's TransactionAwareDataSourceProxy,
which can dynamically discover the transaction context -->
<bean id="transactionAwareDataSource"
class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<constructor-arg ref="dataSource" />
</bean>
<bean class="org.jooq.impl.DataSourceConnectionProvider" name="connectionProvider">
<constructor-arg ref="transactionAwareDataSource" />
</bean>
<!-- Configure the DSL object, optionally overriding jOOQ Exceptions with Spring Exceptions -->
<bean id="dsl" class="org.jooq.impl.DefaultDSLContext">
<constructor-arg ref="config" />
</bean>
<!-- Invoking an internal, package-private constructor for the example
Implement your own Configuration for more reliable behaviour -->
<bean class="org.jooq.impl.DefaultConfiguration" name="config">
<property name="SQLDialect"><value type="org.jooq.SQLDialect">POSTGRES_9_4</value></property>
<property name="connectionProvider" ref="connectionProvider" />
<property name="transactionProvider" ref="transactionProvider" />
</bean>
<!-- BEGIN Services -->
<bean id="loginService" class="com.mz.server.web.service.LoginService">
<constructor-arg>
<ref bean="dsl" />
</constructor-arg>
</bean>
<!-- END Services -->
My problem is that I want loginService to be managed by Spring Security as well. This is my applicationContext-security.xml:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<global-method-security pre-post-annotations="enabled" secured-annotations="enabled" />
<http auto-config="true" >
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
</http>
<authentication-manager >
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
<!-- <beans:bean name="loginService" class="com.mz.server.web.service.LoginService"/> -->
</beans:beans>
If I comment out
<beans:bean name="loginService" class="com.mz.server.web.service.LoginService"/>
I'm getting the error that there's no default constructor - which is true since this class is 1. Already instantiated and 2. Requires a DSLContext object as constructor parameter.
If I let it commented out just nothing happens. No exception of warning is shown. #PreAuthorize appears to be getting ignored ..
How can I resolve this issue?
You can add constructor injection into your XML configuration for the LoginService. Do you autowire DSLContext, too?
This line in your XML is invoking the default constructor:
<beans:bean name="loginService" class="com.mz.server.web.service.LoginService"/>
If you want to do constructor injection of the DSLContext it'd look like this:
<bean name="loginService" class="com.mz.server.web.service.LoginService">
<constructor-arg ref="dslContext"/>
</bean>
This assumes that the bean factory also has a bean for your DSLContext.
You can also try going all annotation or XML configuration, but not mixing and matching.
Related
I used the spring security using saml from this https://github.com/spring-projects/spring-security-saml/tree/master/sample
Now I have my own JSP pages with controller, when I add it to the project, it is stating 404. when try to access http://localhost:2/SAMPLE/pop
My JSP at WEB-INF-jsp-pop.jsp
#Controller
public class ComCont {
#RequestMapping(value="/pop",method=RequestMethod.GET)
public String showHomePage(Map<Object, Object> model) {
System.out.println("gotach");
return "pop";
}
#RequestMapping(value="/hello",method=RequestMethod.GET)
public String showHomePage1(Map<Object, Object> model) {
System.out.println("gotach");
return "hello";
}
}
My servlet context is
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
securityContext.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<!-- Enable auto-wiring -->
<context:annotation-config/>
<!-- Scan for auto-wiring classes in spring saml packages -->
<context:component-scan base-package="org.springframework.security.saml"/>
<!-- Unsecured pages -->
<security:http security="none" pattern="/favicon.ico"/>
<security:http security="none" pattern="/images/**"/>
<security:http security="none" pattern="/css/**"/>
<security:http security="none" pattern="/logout.jsp"/>
<!-- Security for the administration UI -->
<security:http pattern="/saml/web/**" use-expressions="false">
<security:access-denied-handler error-page="/saml/web/metadata/login"/>
<security:form-login login-processing-url="/saml/web/login" login-page="/saml/web/metadata/login" default-target-url="/saml/web/metadata"/>
<security:intercept-url pattern="/saml/web/metadata/login" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<security:intercept-url pattern="/saml/web/**" access="ROLE_ADMIN"/>
<security:custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
</security:http>
<!-- Secured pages with SAML as entry point -->
<security:http entry-point-ref="samlEntryPoint" use-expressions="false">
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
<security:custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
<security:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
</security:http>
<!-- Filters for processing of SAML messages -->
<bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map request-matcher="ant">
<security:filter-chain pattern="/saml/login/**" filters="samlEntryPoint"/>
<security:filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter"/>
<security:filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter"/>
<security:filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/>
<security:filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter"/>
<security:filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFilter"/>
<security:filter-chain pattern="/saml/discovery/**" filters="samlIDPDiscovery"/>
</security:filter-chain-map>
</bean>
<!-- Handler deciding where to redirect user after successful login -->
<bean id="successRedirectHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/"/>
</bean>
<!--
Use the following for interpreting RelayState coming from unsolicited response as redirect URL:
<bean id="successRedirectHandler" class="org.springframework.security.saml.SAMLRelayStateSuccessHandler">
<property name="defaultTargetUrl" value="/" />
</bean>
-->
<!-- Handler deciding where to redirect user after failed login -->
<bean id="failureRedirectHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="useForward" value="true"/>
<property name="defaultFailureUrl" value="/error.jsp"/>
</bean>
<!-- Handler for successful logout -->
<bean id="successLogoutHandler" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
<property name="defaultTargetUrl" value="/logout.jsp"/>
</bean>
<security:authentication-manager alias="authenticationManager">
<!-- Register authentication manager for SAML provider -->
<security:authentication-provider ref="samlAuthenticationProvider"/>
<!-- Register authentication manager for administration UI -->
<security:authentication-provider>
<security:user-service id="adminInterfaceService">
<security:user name="admin" password="admin" authorities="ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<!-- Logger for SAML messages and events -->
<bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger"/>
<!-- Central storage of cryptographic keys -->
<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
<constructor-arg value="classpath:security/samlKeystore.jks"/>
<constructor-arg type="java.lang.String" value="nalle123"/>
<constructor-arg>
<map>
<entry key="apollo" value="nalle123"/>
</map>
</constructor-arg>
<constructor-arg type="java.lang.String" value="apollo"/>
</bean>
<!-- Entry point to initialize authentication, default values taken from properties file -->
<bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
<property name="defaultProfileOptions">
<bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
<property name="includeScoping" value="false"/>
</bean>
</property>
</bean>
<!-- IDP Discovery Service -->
<bean id="samlIDPDiscovery" class="org.springframework.security.saml.SAMLDiscovery">
<property name="idpSelectionPath" value="/WEB-INF/security/idpSelection.jsp"/>
</bean>
<!-- Filter automatically generates default SP metadata -->
<bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.MetadataGenerator">
<property name="extendedMetadata">
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<property name="idpDiscoveryEnabled" value="true"/>
</bean>
</property>
</bean>
</constructor-arg>
</bean>
<!-- The filter is waiting for connections on URL suffixed with filterSuffix and presents SP metadata there -->
<bean id="metadataDisplayFilter" class="org.springframework.security.saml.metadata.MetadataDisplayFilter"/>
<!-- Configure HTTP Client to accept certificates from the keystore for HTTPS verification -->
<!--
<bean class="org.springframework.security.saml.trust.httpclient.TLSProtocolConfigurer">
<property name="sslHostnameVerification" value="default"/>
</bean>
-->
<!-- IDP Metadata configuration - paths to metadata of IDPs in circle of trust is here -->
<bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
<constructor-arg>
<list>
<!-- Example of classpath metadata with Extended Metadata -->
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<constructor-arg>
<bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
<constructor-arg>
<bean class="java.util.Timer"/>
</constructor-arg>
<constructor-arg>
<bean class="org.opensaml.util.resource.ClasspathResource">
<constructor-arg value="/metadata/idp.xml"/>
</bean>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
</bean>
</constructor-arg>
</bean>
<!-- Example of HTTP metadata without Extended Metadata -->
<bean class="org.opensaml.saml2.metadata.provider.HTTPMetadataProvider">
<!-- URL containing the metadata -->
<constructor-arg>
<value type="java.lang.String">http://localhost:12/idp-meta.xml</value>
</constructor-arg>
<!-- Timeout for metadata loading in ms -->
<constructor-arg>
<value type="int">15000</value>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean>
<!-- Example of file system metadata without Extended Metadata -->
<!--
<bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
<constructor-arg>
<value type="java.io.File">/usr/local/metadata/idp.xml</value>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean>
-->
</list>
</constructor-arg>
<!-- OPTIONAL used when one of the metadata files contains information about this service provider -->
<!-- <property name="hostedSPName" value=""/> -->
<!-- OPTIONAL property: can tell the system which IDP should be used for authenticating user by default. -->
<!-- <property name="defaultIDP" value="http://localhost:8080/opensso"/> -->
</bean>
<!-- SAML Authentication Provider responsible for validating of received SAML messages -->
<bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
<!-- OPTIONAL property: can be used to store/load user data after login -->
<!--
<property name="userDetails" ref="bean" />
-->
</bean>
<!-- Provider of default SAML Context -->
<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl"/>
<!-- Processing filter for WebSSO profile messages -->
<bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
<property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
</bean>
<!-- Processing filter for WebSSO Holder-of-Key profile -->
<bean id="samlWebSSOHoKProcessingFilter" class="org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
<property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
</bean>
<!-- Logout handler terminating local session -->
<bean id="logoutHandler"
class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
<property name="invalidateHttpSession" value="false"/>
</bean>
<!-- Override default logout processing filter with the one processing SAML messages -->
<bean id="samlLogoutFilter" class="org.springframework.security.saml.SAMLLogoutFilter">
<constructor-arg index="0" ref="successLogoutHandler"/>
<constructor-arg index="1" ref="logoutHandler"/>
<constructor-arg index="2" ref="logoutHandler"/>
</bean>
<!-- Filter processing incoming logout messages -->
<!-- First argument determines URL user will be redirected to after successful global logout -->
<bean id="samlLogoutProcessingFilter" class="org.springframework.security.saml.SAMLLogoutProcessingFilter">
<constructor-arg index="0" ref="successLogoutHandler"/>
<constructor-arg index="1" ref="logoutHandler"/>
</bean>
<!-- Class loading incoming SAML messages from httpRequest stream -->
<bean id="processor" class="org.springframework.security.saml.processor.SAMLProcessorImpl">
<constructor-arg>
<list>
<ref bean="redirectBinding"/>
<ref bean="postBinding"/>
<ref bean="artifactBinding"/>
<ref bean="soapBinding"/>
<ref bean="paosBinding"/>
</list>
</constructor-arg>
</bean>
<!-- SAML 2.0 WebSSO Assertion Consumer -->
<bean id="webSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerImpl"/>
<!-- SAML 2.0 Holder-of-Key WebSSO Assertion Consumer -->
<bean id="hokWebSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>
<!-- SAML 2.0 Web SSO profile -->
<bean id="webSSOprofile" class="org.springframework.security.saml.websso.WebSSOProfileImpl"/>
<!-- SAML 2.0 Holder-of-Key Web SSO profile -->
<bean id="hokWebSSOProfile" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>
<!-- SAML 2.0 ECP profile -->
<bean id="ecpprofile" class="org.springframework.security.saml.websso.WebSSOProfileECPImpl"/>
<!-- SAML 2.0 Logout Profile -->
<bean id="logoutprofile" class="org.springframework.security.saml.websso.SingleLogoutProfileImpl"/>
<!-- Bindings, encoders and decoders used for creating and parsing messages -->
<bean id="postBinding" class="org.springframework.security.saml.processor.HTTPPostBinding">
<constructor-arg ref="parserPool"/>
<constructor-arg ref="velocityEngine"/>
</bean>
<bean id="redirectBinding" class="org.springframework.security.saml.processor.HTTPRedirectDeflateBinding">
<constructor-arg ref="parserPool"/>
</bean>
<bean id="artifactBinding" class="org.springframework.security.saml.processor.HTTPArtifactBinding">
<constructor-arg ref="parserPool"/>
<constructor-arg ref="velocityEngine"/>
<constructor-arg>
<bean class="org.springframework.security.saml.websso.ArtifactResolutionProfileImpl">
<constructor-arg>
<bean class="org.apache.commons.httpclient.HttpClient">
<constructor-arg>
<bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager"/>
</constructor-arg>
</bean>
</constructor-arg>
<property name="processor">
<bean class="org.springframework.security.saml.processor.SAMLProcessorImpl">
<constructor-arg ref="soapBinding"/>
</bean>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="soapBinding" class="org.springframework.security.saml.processor.HTTPSOAP11Binding">
<constructor-arg ref="parserPool"/>
</bean>
<bean id="paosBinding" class="org.springframework.security.saml.processor.HTTPPAOS11Binding">
<constructor-arg ref="parserPool"/>
</bean>
<!-- Initialization of OpenSAML library-->
<bean class="org.springframework.security.saml.SAMLBootstrap"/>
<!-- Initialization of the velocity engine -->
<bean id="velocityEngine" class="org.springframework.security.saml.util.VelocityFactory" factory-method="getEngine"/>
<!-- XML parser pool needed for OpenSAML parsing -->
<bean id="parserPool" class="org.opensaml.xml.parse.StaticBasicParserPool" init-method="initialize">
<property name="builderFeatures">
<map>
<entry key="http://apache.org/xml/features/dom/defer-node-expansion" value="false"/>
</map>
</property>
</bean>
<bean id="parserPoolHolder" class="org.springframework.security.saml.parser.ParserPoolHolder"/>
</beans>
web.xml
<servlet>
<servlet-name>saml</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>saml</servlet-name>
<url-pattern>/saml/web/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
What is I'm missing here? I'm new to Spring MVC. I know some basics.
URL pattern Syntax :
http://localhost:2/{Your project_name}/{url-pattern}/{jsp name}
Try to hit this url,
http://localhost:2/SAMPLE/saml/web/pop
else, Change your dispatcher-servlet Servlet mapping to like this,
<servlet-mapping>
<servlet-name>saml</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Now try this url, http://localhost:2/SAMPLE/pop
Change your Controller RequestMapping to like this,
#Controller
public class ComCont {
#RequestMapping(value="/pop",method=RequestMethod.GET)
public String showHomePage(Map<Object, Object> model) {
System.out.println("gotach");
return "pop";
}
}
Based on the content you have provided for web.xml and securityContext.xml, they looks fine, so doesn't look like filter chain issue. Moreover you are getting 404 which means there is some issue with URL, if you were getting 5xx then it could have been because of some server issue like filter chain. Or 403 if it was because of security or access issue. Below are details on resolution:
Assuming you do have (must be having) saml-servlet.xml, use below instead of what you have provided:
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
Based on above, you can understand (I think you are already doing) that you need to have your JSP's in /WEB-INF/jsp/
I am not sure what you are trying to achieve from your controller code but if you are trying to render your pop.jsp from the URL you mentioned then use below code in controller:
#RequestMapping(value="/pop",method=RequestMethod.GET)
public ModelAndView showHomePage(ModelMap model, HttpServletRequest request) {
System.out.println("I am in pop .. Lets rock ..");
return new ModelAndView("pop", "pop", "I am coming from controller");
}
Three arguments to ModelAndView constructor
Name of JSP, this case Spring will resolve it as pop.jsp and should be located under /WEB-INF/jsp/
Name of the object you want to pass to the JSP page, in this case name of the object is "pop", so you can use ${pop} in your JSP and you will see "I am coming from controller" getting rendered. This is just a String but you can pass a POJO which can be accessed using JSON notation in your JSP.
Actual object, String in this case.
Now, coming to your URL - http://localhost:2/SAMPLE/pop, I am pretty sure that you know this but I feel responsible to cover this, so - your WAR file name should be SAMPLE.war because that's your web context. If it is not then you have to use same name, lets say for springapp.war, your URL will be http://localhost:2/springapp. This is basic part of your URL.
Now you were using http://localhost:2/SAMPLE/pop which by all means is incorrect because your DispatcherServlet is configured for URL mapping of /saml/web/*. So, all your web request should have URL as http://localhost:2/SAMPLE/saml/web/. Whatever is the DispatcherServlet mapping should come after your URL context path - http://localhost:2/SAMPLE
Now, if you want to hit the /pop controller then you have start building your URL after DispatcherServlet mapping, so your URL will become http://localhost:2/SAMPLE/saml/web/pop.
If you use exact above URL and do the code modifications as I suggested then I am positive that your "pop.jsp" will be displayed.
Please note that your controller method is accepting only GET requests - RequestMethod.GET, so you have to hit the URL from browser. In case if you are sending Ajax POST requests from JSP then controller mapping should have RequestMethod.POST.
Also, please take care of using exact URL while taking care of slashes /
I am a newbie to spring-security.I have a issue with #Autowired annotation.
Below is my spring-security.xml file:
<http pattern="/login" security="none" />
<http pattern="/signup" security="none" />
<http pattern="/views/**" security="none" />
<http pattern="/createUser" security="none" />
<http pattern="/practice" security="none" />
<http use-expressions="true" authentication-manager-ref="authenticationManager">
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<form-login login-page="/login" default-target-url="/home"
authentication-failure-url="/login" username-parameter="username"
password-parameter="password" login-processing-url="/j_spring_security_check" />
<logout logout-success-url="/login" invalidate-session="true"
logout-url="/j_spring_security_logout" delete-cookies="JSESSIONID" />
<session-management invalid-session-url="/login">
<concurrency-control max-sessions="1"
expired-url="/login" />
</session-management>
</http>
<authentication-manager id="authenticationManager">
<authentication-provider user-service-ref="userDetailsService" />
</authentication-manager>
<beans:bean id="userDetailsService" class="com.practice.service.UserDetailsServiceImpl" />
<beans:bean name="
passwordEncoder "
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
This is my spring-servlet.xml configuration:
<context:annotation-config/>
<context:component-scan base-package="com.practice" />
<mvc:resources mapping="/views/**" location="/views/" />
<mvc:annotation-driven />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations"
value="classpath:com/practice/resources/database.properties"></property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:com/practice/resources/hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
I would request for signup page, and after filling the necessary details , it hits my controller , where i save the user in the database, then i authenticate the user, in the request against the one which i stored in the database. I followed this stackoverflow post for guidance.
The strange thing is the autowiring is not happening in the class, where i implement the UserDetailsService interface :
#Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
PasswordEncoder passwordEncoder;
#Autowired
UserService userService;
#Override
public UserDetails loadUserByUsername(String arg0)
throws UsernameNotFoundException {
System.out.println("ddfddd");
return null;
}}
Whereas autowiring is taking place in other service classes , where i autowired the same fields as mentioned above !!
The same thing happens when i do a login , and when i debugged , the fields are null ! and also in the classes where i wrote my CustomAuthenticationProvider !
Any suggestion ?? If there is any mistake in my configuration do correct me.
Update
I am getting the following error,
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.practice.service.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
when i remove #Service annotation and when i add context:annotation-config
If you have defined a UserService bean with an #Component annotation, which is picked up by the component scan in spring-servlet.xml, then the problem could be, that spring-servlet.xml is a child application context from spring-security.xml. In that case, beans from the security context aren't able to access any beans from the child context, only the other way round. So you have to make sure, that all required beans are accessible from the spring-security.xml context (e.g. by specifying all beans explicitly or by moving the annotation-config and component-scan elements in the spring-security.xml context).
Rather new to Java coming from a c# background.
What I am trying to achieve is just to expose a method to jConsole via jmx and rim.
When I run my service and open jConsole I can see the method there and all looks good, now the problem comes in when i try to run this method via the console. The error I get is "Problem invoking helloWorld : java.rmi.UnmarshalException: Error unmarshaling return; nested exception is: java.lang.ClassNotFoundException: org.springframework.jdbc.CannotGetJdbcConnectionException (no security manager: RMI class loader disabled)".
The method im trying to expose is
#ManagedOperation
public int helloWorld() throws Exception {
return jdbcTemplate.queryForInt(sql);
}
Here is my applicationContext file
<!-- this bean must not be lazily initialized if the exporting is to happen -->
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="assembler" ref="assembler" />
<property name="namingStrategy" ref="namingStrategy" />
<property name="autodetect" value="true" />
</bean>
<bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />
<!-- will create management interface using annotation metadata -->
<bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource" />
</bean>
<!-- will pick up the ObjectName from the annotation -->
<bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
<property name="attributeSource" ref="jmxAttributeSource" />
</bean>
<context:component-scan base-package="com.bulks" />
<!-- enable annotations like #Autowired, which you also most likely need -->
<context:annotation-config/>
<bean class="com.bulksms.resources.HelloWorldResource"/>
<!-- setup basic datasource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/apu"></property>
<property name="username" value="root"></property>
<property name="password" value="password"></property>
</bean>
<!-- jdbcTemplate bean -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
What am i missing so my method can be executed from the console?
-----SOLUTION------
So after hacking away at this for long i tried to put the sql part in its own method and then just call the method in the helloWorld method.... Low and behold!!!! SUCCESS!!!
public int helloWorld() throws Exception {
setValueFromQuery();
return value;
}
private void setValueFromQuery() {
this.value = jdbcTemplate.queryForInt(sql);
}
You exception is a nested exception, so its happened on on your application,
java.lang.ClassNotFoundException: org.springframework.jdbc.CannotGetJdbcConnectionException
So its say that there is a missing class, which could be the jdbc, make sure that you have it in your class path.
so if you have it, the check the connection criteria to your DB.
In my application users can manipulate with things, that linked only to them. All users have same role in spring security. So, to forbid user to view not his stuff, I need to implement in some controllers methods my own function to validate users rights.
public void securityValidation(User currentUser, Thing thing) {
if(!thing.has(currentUser)) {
log.warn("Security Control. User: " + user .getId());
}
}
I think It's not cool. It's hard to find in code is the method secured or not.
May be Spring has more elegant way for this task?
Or may be I can write my own annotation for securing methods? Do I need annotation processor for that?
You are referring to Domain Object Security, it is not part of the base security package. Spring Security ACL is what you need, with it you can assert ownership of actual items, for example user 123 can edit item 789. The code below makes sure the current user has admin rights over the entity he is editing:
#PreAuthorize("hasPermission(#entity, 'ADMINISTRATION')")
public SomeEntity update(SomeEntity entity) {
...
}
But keep in mind, you now have to manage those permissions and give/remove them to individual users. There is also a way to do it as part of a group. You can say user 123 and 345 belong to GROUP_SOME_ID and then if you give GROUP_SOME_ID admin permission over an object, users 123 and 345 will get them automatically. Removing user 123 from the group would automatically remove his permission as well.
---- UPDATE ------
Below is sample application context that wires up Spring Security ACL:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator" ref="permissionEvaluator" />
</bean>
<!-- We'll rely on the standard AclPermissionEvaluator implementation -->
<bean class="org.springframework.security.acls.AclPermissionEvaluator" id="permissionEvaluator">
<constructor-arg ref="aclService" />
<property name="sidRetrievalStrategy" ref="sidRetrievalStrategy" />
<property name="permissionFactory" ref="permissionFactory"/>
</bean>
<bean class="org.springframework.security.acls.domain.SidRetrievalStrategyImpl" id="sidRetrievalStrategy" >
<constructor-arg ref="roleHierarchy" />
</bean>
<!-- Declare an acl service -->
<bean class="org.springframework.security.acls.jdbc.JdbcMutableAclService" id="aclService">
<constructor-arg ref="dataSource" />
<constructor-arg ref="lookupStrategy" />
<constructor-arg ref="aclCache" />
<property name="classIdentityQuery" value="select currval(pg_get_serial_sequence('acl_class', 'id'))" />
<property name="sidIdentityQuery" value="select currval(pg_get_serial_sequence('acl_sid', 'id'))" />
</bean>
<!-- Declare a lookup strategy -->
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="dataSource" />
<constructor-arg ref="aclCache" />
<constructor-arg ref="aclAuthorizationStrategy" />
<constructor-arg ref="permissionGrantingStrategy" />
<property name="permissionFactory" ref="permissionFactory"/>
</bean>
<bean id="permissionFactory" class="org.springframework.security.acls.domain.DefaultPermissionFactory" />
<!-- Declare an acl cache -->
<bean id="aclCache" class="org.springframework.security.acls.domain.SpringCacheBasedAclCache">
<constructor-arg>
<bean class="com.example.NoOpCache">
<constructor-arg value="aclCache" />
</bean>
</constructor-arg>
<constructor-arg ref="permissionGrantingStrategy" />
<constructor-arg ref="aclAuthorizationStrategy" />
</bean>
<!-- Declare an acl authorization strategy -->
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMIN" />
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMIN" />
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMIN" />
</bean>
</list>
</constructor-arg>
</bean>
<bean id="permissionGrantingStrategy" class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy" >
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger" />
</constructor-arg>
</bean>
<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_USER > ROLE_ANONYMOUS
ROLE_SUPER_USER > ROLE_USER
ROLE_ADMIN > ROLE_SUPER_USER
</value>
</property>
</bean>
</beans>
#PreAuthorize("hasRole('ROLE_ADMIN')")
above any controller method you want to restrict to admins, for example.
Making sure you define methodSecurityExpressionHandler bean in web context.
I want to configure Spring MVC to serve dynamic files mixed with static files, like this (URL => File):
/iAmDynamic.html => /WEB-INF/views/iAmDynamic.html.ftl
/iAmAlsoDynamic.js => /WEB-INF/views/iAmAlsoDynamic.js.ftl
/iAmStatiHtml => /iAmStatic.html
The DispatchServlet is mapped to /, annotation-based MVC configuration is enabled and I have a view controller like this (Simplified):
#Controller
public class ViewController
{
#RequestMapping("*.html")
public String handleHtml(final HttpServletRequest request)
{
return request.getServletPath();
}
#RequestMapping("*.js")
public String handleJavaScript(final HttpServletRequest request)
{
return request.getServletPath();
}
}
The spring config looks like this:
<context:component-scan base-package="myPackage" />
<mvc:default-servlet-handler />
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/views/" />
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true" />
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
</bean>
Unfortunately it doesn't work. When this <mvc:default-servlet-handler /> is active then I can only access the iAmStatic.html file. When I disable the default-servlet-handler then only the dynamic stuff works. But I want both at once and that's exactly what this default-servlet-handler should do, or not? Where is the error here?
I had similar problem, none of the requests were getting mapped to the Spring Controllers:
I discovered I was missing this in spring config xml:
<mvc:annotation-driven/>
It seems with , this is necessary. From documentation, the purpose of doing this is:
Configures the annotation-driven Spring MVC Controller programming model
I will also let DefaultServlet handle static content requests.
So your spring config should look like:
<context:component-scan base-package="myPackage" />
<!-- Define location and mapping of static content -->
<mvc:resources location="/static/" mapping="/static/**"/>
<mvc:default-servlet-handler />
<mvc:annotation-driven/>
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/views/" />
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true" />
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
</bean>
Hope this helps!
You need to define two important configurations
<mvc:annotation-driven/>
<mvc:default-servlet-handler />
<mvc:annotation-driven/> will enable your default infrastructure beans where as <mvc:default-servlet-handler /> will configure a handler for serving static resources by forwarding to the Servlet container's default Servlet.
Also don't forget the mvc name space i.e xmlns:mvc="http://www.springframework.org/schema/mvc"
My complete config file (using TilesViewResolver) looks like below
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
<!--
Configures a handler for serving static resources by forwarding to the
Servlet container's default Servlet.
-->
<mvc:default-servlet-handler />
<mvc:view-controller path="/" view-name="welcome"/>
<mvc:view-controller path="/home" view-name="welcome"/>
<bean class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles.xml</value>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.tiles3.TilesViewResolver">
<property name="order" value="1"/>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="2"/>
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
Also if you have multiple HandlerMapping considering ordering them. For one for which you don't provide order explicitly Spring treats it with lowest precedence.
I think that the view name you are returning from the ViewController is invalid. I expect that request.getServletPath() returns a blank string for all URLs, because the path to your servlet is probably / and the Java documentation says that getServletPath() returns a blank string for that path. Therefore the FreeMarker view resolver is probably ignoring the view name because it wouldn't know what to show.
However using a controller class with #RequestMapping is probably not the ideal way to go about this task anyway. Spring includes a ContentNegotiatingViewResolver which automatically determines the correct view depending on the content type. This overview of ContentNegotiatingViewResolver explains how to set it up.