How custom authentication-provider works - spring

Good day people.
Please help. Can not understands how my custom authentication-provider should be triggered.
I have:
Spring-context.xml
<security:http pattern="/login" security="none" />
<security:http auto-config="true" use-expressions="true">
<security:form-login login-page="/login"/>
<security:intercept-url pattern="/" access="hasRole('ROLE_USER')"/>
<security:form-login authentication-failure-url="www.google.com"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="userSecurityService"/>
</security:authentication-manager>
<bean id="webContentDAOImpl" class="demidov.pkg.persistence.WebContentDAOImpl">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>
<bean id="userSecurityService" class="demidov.pkg.persistence.UserSecurityService">
<property name="webContentDAOIF" >
<ref bean="webContentDAOImpl"/>
</property>
</bean>
Login Controller:
#Controller
public class LoginController {
#RequestMapping(value="/login", method=RequestMethod.GET)
public String login() {
return "login";
}
#RequestMapping(value="/security/j_spring_security_check", method=RequestMethod.POST)
public String access() {
return "redirect:/";
}
}
Login JSP page:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="security/j_spring_security_check" method="post">
UserName: <input type="text"/> <br>
Password: <input type="password"/> <br>
<br>
<input type="submit"/>
</form>
</body>
</html>
Custom principal resolver:
public class UserSecurityService implements UserDetailsService{
WebContentDAOIF webContentDAOIF;
public WebContentDAOIF getWebContentDAOIF() {
return webContentDAOIF;
}
public void setWebContentDAOIF(WebContentDAOIF webContentDAOIF) {
this.webContentDAOIF = webContentDAOIF;
}
#Override
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException {
UserDetails userDetails = null;
TheUser theUser = webContentDAOIF.fetchUserByName(userName);
userDetails = new User(theUser.getUserEmale(), theUser.getUserPassword(), true, true, true, true, getAthorities(theUser.getRoleAccess()));
return userDetails;
}
public Collection<GrantedAuthority> getAthorities(String role) {
List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2);
authList.add(new SimpleGrantedAuthority(" "));
if ( role.equals("ROLE_USER")) {
authList.add(new SimpleGrantedAuthority("ROLE_USER"));
}
// Return list of granted authorities
return authList;
}
}
I just can not understand how my custom principal resolver should work with security. How it should be triggered and by what??? When I put wrong username and password on login page it seems not work with my UserSecurityService and just simply redirect me on login page again because of my hasRole(ROLE_USER) in spring-context.xml . I believe that j_spring_security_check may do something, but so doubt of it. Please help me to understand.

kindly refer to below mentioned link, may be of some help :-
spring security custom authentication

method loadUserByUsername is having param userName which is having value posted from browser that userName is compared with DB and password is fetched from DB and passed to UserDetail object which is having a password posted from browser so now it will compare the passwords internally and acts accordingly for authentication

Related

Spring Web Flow flowExecutionUrl is empty

I'm making simple order-flow via Spring Web Flow, also i have Spring MVC on my project. I've been doing everything according to guides, but my web-app doesn't react to my flow at all. Spring Web Flow Config:
#Configuration
#ComponentScan(basePackages = "config")
public class WebFlowConfig extends AbstractFlowConfiguration {
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.setDevelopmentMode(true).build();
}
#Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(
Collections.singletonList(this.webMvcConfig.resourceViewResolver()));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
#Autowired
private DispatcherConfig webMvcConfig;
#Bean
public FlowDefinitionRegistry flowRegistry() {
FlowDefinitionRegistry registry = getFlowDefinitionRegistryBuilder().addFlowLocation("/WEB-INF/flows/order/flowcnf.xml","order").build();
return registry;
}
#Bean
public FlowExecutor flowExecutor() {
return
getFlowExecutorBuilder(flowRegistry()).build();
}
#Bean
public FlowHandlerMapping flowHandlerMapping(){
final FlowHandlerMapping handeler = new FlowHandlerMapping();
handeler.setFlowRegistry(flowRegistry());
handeler.setFlowUrlHandler(defaultFlowUrlHandler());
return handeler;
}
#Bean
public DefaultFlowUrlHandler defaultFlowUrlHandler(){
return new DefaultFlowUrlHandler();
}
#Bean
public FlowHandlerAdapter adapter(){
FlowHandlerAdapter adapter = new FlowHandlerAdapter();
adapter.setFlowUrlHandler(defaultFlowUrlHandler());
adapter.setFlowExecutor(flowExecutor());
return adapter;
}
}
As I said I'm using Spring MVC maybe the problems occurs due to it.
Code snippet below must run "thankCustomer" view-state, but it doesn't.
I get 404 eror if i click the link.
<a class=button href="${flowExecutionUrl}&_eventId=thankCustomer">Замовити!</a>
And the flow code:
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
start-state="identify">
<var name="order" class="entity.BookOrder"/>
<subflow-state id="identify" subflow="order/custom" >
<output name="user" value="order.custName" />
<transition on="userIsReady" to="buildOrder"/>
</subflow-state>
<subflow-state id="buildOrder" subflow="order/build">
<input name="order" value="order" />
<transition to="takePayment" on="orderBuilt" />
</subflow-state>
<subflow-state id="takePayment" subflow="order/takePayment" >
<input name="order" value="order"/>
<transition on="paymentTaken" to="saveOrder" />
</subflow-state>
<action-state id="saveOrder">
<evaluate expression="userServiceImpl.addOrder(order.custName,order)"/>
<transition to="thankCustomer" />
</action-state>
<view-state id="thankCustomer" view="/WEB-INF/pages/greeting.jsp" >
<transition to="end-point" />
</view-state>
<end-state id="end-point"/>
<global-transitions>
<transition on="cancel" to="end-point" />
</global-transitions>
</flow>
I've tried to put flow id (order) instead of empty flowExecutionUrl, but still the same eror, I'll be grateful for any kinda help.
I needed to set "order" to my FlowHandlerMapping Bean, couse i already had 2 viewResolvers.

Spring Security with hibernate : hasRole() is not working in config

I am trying to implement Spring Security for my Spring + Hibernate project.
But the hasRole('SUPER_ADMIN') that i write in the intercept-url tag is not working.
Please find the config that i have done below.
springSecurity.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/admin**" access="hasRole('SUPER_ADMIN')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login login-page="/login" default-target-url="/welcome" authentication-failure-url="/login?error" username-parameter="username"
login-processing-url="/loginCheck" password-parameter="password" />
<logout logout-success-url="/login?logout" />
<!-- enable csrf protection -->
<csrf />
</http>
<authentication-manager>
<authentication-provider user-service-ref="myUserDetailsServices">
<password-encoder hash="bcrypt" />
</authentication-provider>
</authentication-manager>
I am using the following auth provider
public class MyUserDetailsServices implements UserDetailsService {
private UserDao userDao;
#Override
#Transactional
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
User user = userDao.findByEmail(username);
if (user == null) {
throw new UsernameNotFoundException("User " + username + " not found");
}
List<GrantedAuthority> authorities = buildUserAuthority(user.getRoles());
return buildUserForAuthentication(user, authorities);
}
private org.springframework.security.core.userdetails.User buildUserForAuthentication(User user, List<GrantedAuthority> authorities) {
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), true, true, true, true, authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<Role> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
for (Role userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRoleName()));
}
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);
return Result;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
The The above code is working fine. I am able to get the correct role and buildUserForAuthentication() method is returned with the SUPER_ADMIN role added in the authorities.
But still the hasRole('SUPER_ADMIN') is not working. I am not able to access the page http://127.0.0.1:8080/myproj/admin. The user is getting authenticated and logged in. But the above url is getting redirected to /403 (Access Denied).
Am i missing something? Please help.!
The hasRole is working well. What is not working in your code is your wildcard on your springSecurity.xml.
Change this
<intercept-url pattern="/admin**" access="hasRole('SUPER_ADMIN')" />
to
<intercept-url pattern="/admin/**" access="hasRole('SUPER_ADMIN')" />
Not sure why and how, but spring seems to add a leading slash why validating your url.
so having /admin/** will have the same effect as your intended /admin**.
Got this rectified by adding 'ROLE_' to the rolename. Made it as ROLE_SUPER_ADMIN and it started working. I am assuming that every role should be prefixed with 'ROLE_' for spring security to work properly.
Thanks #storm_buster for the tip. :)

How Authentication manager verifies Credentials?

I am using spring security in my web application.
Here we have authentication-manager & authentication-provider where we are providing authenticate user details directly or by an service.
Like:
<authentication-manager>
<authentication-provider user-service-ref="loginService" />
</authentication-manager>
How it is internally performing the verifications. Where is the verification logic present ?
What is going on internally ?
Can anyone suggest with explanation.
Spring security Javadoc is your friend !
AuthenticationManager is an interface. The default implementation is ProviderManager that gets a list of AuthenticationProvider. Each AuthenticationProvider is tried in sequence until one can decide for the authentication credentials proposed.
Here, the <authentication-provider user-service-ref="loginService" /> declares a DaoAuthenticationProvider. The DaoAuthenticationProvider loads user information from the UserDetailsService (here loginService) and compares the username/password combination with the values supplied at login. If all is fine, it populates an AuthenticationToken with the values retrieved from loginService and passes id back to the AuthenticationManager. If credentials are wrong, it throws an AuthenticationException
It goes like this :
Security-application-context.xml :
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="LoginServiceImpl">
<security:password-encoder ref="encoder"/>
</security:authentication-provider>
</security:authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11" />
</beans:bean>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="LoginServiceImpl"/>
<beans:property name="passwordEncoder" ref="encoder"/>
</beans:bean>
In the above code, you can see authentication manager indicates user-service-ref is LoginServiceImpl and use BCrypt encode with 11 rounds for encryption. Then It looks for Classes with LoginServiceImpl, mentioned below :
#Transactional
#Service("userDetailsService")
public class LoginServiceImpl implements UserDetailsService{
#Autowired private PersonDAO personDAO;
#Autowired private Assembler assembler;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException,DataAccessException {
Person person = personDAO.findPersonByUsername(username.toLowerCase());
if(person == null) { throw new UsernameNotFoundException("Wrong username or password");}
return assembler.buildUserFromUserEntity(person);
}
public LoginServiceImpl() {
}
}
As you see it calls a database method by searching in the database for the user. If found, then a new person is build based upon UserDetails class, as below, I am doing it in assembler :
#Service("assembler")
public class Assembler {
#Transactional(readOnly = true)
User buildUserFromUserEntity(Person userEntity){
String username = userEntity.getUsername().toLowerCase();
String password = userEntity.getPassword();
boolean enabled = userEntity.isEnabled();
boolean accountNonExpired = userEntity.isAccountNonExpired();
boolean credentialsNonExpired = userEntity.isCredentialsNonExpired();
boolean accountNonLocked = userEntity.isAccountNonLocked();
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(username,password,enabled,accountNonExpired,credentialsNonExpired,accountNonLocked,authorities);
}
}
These other guys indicate if account is not expired, not locked, and other details. I hope you followed the procedure.

How to Implement security login and logout in spring?

Please go through the following code:
I have been using the following class to authenticate the user:
#Controller
public class AdminLoginController
{
#RequestMapping(value = "/loginForm", method ={RequestMethod.GET,RequestMethod.POST})
public String showForm(ModelMap model)
{
return GlobalConstants.LOGIN_PAGE;}
#RequestMapping(value = "/login" ,method ={RequestMethod.POST, RequestMethod.GET})
public String processForm(#ModelAttribute("loginForm")AdminLoginForm loginForm, BindingResult result , HttpServletRequest request, HttpServletResponse response, ModelMap model)
{
try{
AdminLoginWorker worker=new AdminLoginWorker();
boolean status=worker.validateUser(loginForm);
if(status)
{
if("superAdmin".equalsIgnoreCase(loginForm.getUserType()))
{
dtoBean.setEmp_id(loginForm.getUserName());
session.setAttribute("dtoBean", dtoBean);
return GlobalConstants.SUPERADMIN_HOME_PAGE;
}
if("Admin".equalsIgnoreCase(loginForm.getUserType()))
{
dtoBean.setEmp_id(loginForm.getUserName());
session.setAttribute("dtoBean", dtoBean);
return GlobalConstants.HOME_PAGE;
}
}catch(Exception e){
e.printStackTrace();
}
return GlobalConstants.LOGIN_PAGE;
}
and for the logout:
#RequestMapping(value = "/logout", method ={RequestMethod.GET,RequestMethod.POST})
public ModelAndView logoutForm(HttpServletRequest request)
{
HttpSession session = request.getSession(false);
session.invalidate();
return new ModelAndView( GlobalConstants.LOGIN_PAGE);
}
I called the DAO method to validate from database using:
public class AdminLoginWorker{
public boolean validateUser(AdminLoginForm loginForm){
try{ con=DBConnection.getConnection();
query="select userType from login where emp_id=? and pwd=?";
pstmt.setInt(1,loginForm.getUserName());
pstmt.setString(2,loginForm.getPassword());
if(rs.next()){
loginForm.setUserType(rs.getString(1));
return true;}
so now I wants implement the spring security in my web application so I have tried the following in spring-context.xml:
<http auto-config="true">
<intercept-url pattern="/**" access="isAuthenticated"/> <!-- this means all URL in this app will be checked if user is authenticated -->
<form-login/> <!-- -->
<logout logout-url="/logout" logout-success-url=""/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="sachin" password="sachin123" authorities="Admin"/>
</user-service>
</authentication-provider>
In above security-context.xml file I wants to add data source so that the user will be verified using database so I have been using the below DBCOnnection class for connectivity with Mysql:
public class DBConnection {
private static Connection con=null;
public static Connection getConnection()
{
try{
if(con==null){
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/portal",
"root", "root");
}
}catch(Exception e){
e.printStackTrace();
}
return con;
}
}
Now the question i,
How to put the above datasource in security-context.xml file or
Is there any way i can reference from security-context.xml file to DBConnection class for implementing the spring security login authentication.
does anyone have idea to solve the issue?
It seems to me that you are doing of fair amount of wheel reinvention. Everything you are trying to do manually to can easily be handled by Spring Security without writing code, just using the appropriate configuration.
Check out this and this blog post for more details

Spring security Custom hash algorithm

I have a Spring Project that has been authenticated using Spring Security.
Spring Security code snippet :
<authentication-manager>
<authentication-provider>
<password-encoder hash="md5"/>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
SELECT users.LOGIN_NAME AS username,
users.PASSWD_HASH AS password , users.status as enabled
FROM RV_USER users
WHERE users.LOGIN_NAME=?"
authorities-by-username-query="
select users.LOGIN_NAME as username, authorities.ROLE_DESC as authority
from RV_ROLE authorities, RV_USER users
where authorities.ROLE_ID=users.ROLE_ID
and users.LOGIN_NAME=?"
/>
</authentication-provider>
</authentication-manager>
I want to use a custom hash algorithm rather than md5 or something else.
You can create your own PasswordEncoder implementation. For example:
import org.springframework.security.crypto.password.PasswordEncoder;
public class CustomPasswordEncoder implements PasswordEncoder {
public String encode(CharSequence rawPassword) {
return null; // TODO implement
}
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return null; // TODO implement
}
}
You can then use CustomPasswordEncoder with password-encoder#ref For example:
<authentication-manager>
<authentication-provider>
<password-encoder ref="customPasswordEncoder/>
...
</authentication-provider>
</authentication-manager>

Resources