Hi Patrick,
I just finished (10 mins ago) implementing my Spring Security service
over the top of the Requestfactory.
I am sure there are some holes (not security ones, just stuff I have
missed) but here is what I did.
I have a user entity (that represents the user). this entity has the
username, and the password.
@Entity
@Configurable
public class IsuproUser {
private String username;
private String password;
@OneToOne
private Person person;
// clear or sha256
private String passwordEncoding;
private boolean enabled;
}
/* and example table insert for a user then looks like
INSERT INTO isupro_user (password, username,person, enabled,
password_encoding) VALUES
('5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8','rbuckland',
1, 1, 'sha256')
sha256 value is 'password'.
echo -n password | sha256sum
*/
I have a fairly clean META-INF/spring/applicationContext-security.xml
file.
<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-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<!-- HTTP security configurations -->
<http auto-config="true" use-expressions="true">
<form-login login-processing-url="/resources/
j_spring_security_check"
login-page="/login.jspx"
authentication-failure-url="/login.jspx?
login_error=t" />
<logout logout-url="/resources/j_spring_security_logout" />
<!-- Configure these elements to secure URIs in your application --
>
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" /
>
<intercept-url pattern="/gwtRequest/**"
access="isAuthenticated()" />
<intercept-url pattern="/isupro.jsp" access="isAuthenticated()" />
<intercept-url pattern="/**" access="permitAll" />
</http>
<beans:bean
class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"
id="passwordEncoder">
<beans:constructor-arg value="256" />
</beans:bean>
<beans:bean id="myUserDetailsService"
class="isupro.security.IsuproUserDetailsService" />
<!-- Configure Authentication mechanism -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="myUserDetailsService">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
</authentication-manager>
</beans:beans>
So I have (hopefully) secured the app, on the isupro.jsp (this is the
GWT bootstrap).
I have a UserDetails class. Which is just a minor extension on the
spring one (seems there is some depecation for this "User" class.. but
I moved on :-) worry about that later ).
public class IsuproUserDetails extends User {
private IsuproUser isuproUser;
private static final long serialVersionUID = 1L;
@SuppressWarnings("deprecation")
public IsuproUserDetails(IsuproUser isuproUser) {
super(isuproUser.getUsername(), isuproUser.getPassword(),
isuproUser.getEnabled(),true, true, true, getAuthorities(false));
this.setIsuproUser(isuproUser);
}
// threading issue here .. change
private static GrantedAuthority[] getAuthorities(boolean isAdmin)
{
List<GrantedAuthority> authList = new
ArrayList<GrantedAuthority>(2);
authList.add(new GrantedAuthorityImpl("ROLE_USER"));
if (isAdmin) {
authList.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
}
return authList.toArray(new GrantedAuthority[] {});
}
public void setIsuproUser(IsuproUser isuproUser) {
this.isuproUser = isuproUser;
}
public IsuproUser getIsuproUser() {
return isuproUser;
}
}
Now we have two more classes to care about. first, the one that
SpringSecurity needs, the UserDetails service. I use JPA (it was an
app based off ROO (side note: I find ROO cumbersome! :-/ )
public class IsuproUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws
UsernameNotFoundException, DataAccessException {
IsuproUser isuproUser =
IsuproUser.findUserByUsername(username);
if (isuproUser != null) {
return new IsuproUserDetails(isuproUser);
} else {
throw new UsernameNotFoundException("Username : " +
username + " : was not found");
}
}
}
And then the one that the GWT RequestFactory needs.
public class IsuproUserInformation extends UserInformation {
public IsuproUserInformation(String redirectUrl) {
super(redirectUrl);
}
@Override
public String getEmail() {
return "
em...@address.com";
}
@Override
public Long getId() {
if
(SecurityContextHolder.getContext().getAuthentication().isAuthenticated())
{
IsuproUserDetails userdetails = (IsuproUserDetails)
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return userdetails.getIsuproUser().getId();
} else {
return -1L;
}
}
@Override
public String getLoginUrl() {
return "/login.jspx";
}
@Override
public String getLogoutUrl() {
return "/logout";
}
@Override
public String getName() {
if
(SecurityContextHolder.getContext().getAuthentication().isAuthenticated())
{
IsuproUserDetails userdetails = (IsuproUserDetails)
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return userdetails.getIsuproUser().getUsername(); // this
could be the name of the getPerson()
} else {
return "Guest";
}
}
@Override
public boolean isUserLoggedIn() {
return
SecurityContextHolder.getContext().getAuthentication().isAuthenticated();
}
@Override
public void setId(Long id) {
// we don't allow setting the ID
}
}
And finally, telling the GWT Requestfactory about this UserInformation
class.
<servlet>
<servlet-name>requestFactory</servlet-name>
<servlet-
class>com.google.gwt.requestfactory.server.RequestFactoryServlet</
servlet-class>
<init-param>
<param-name>userInfoClass</param-name>
<param-value>isupro.security.IsuproUserInformation</param-value>
</init-param>
</servlet>
So now, If i navigate to /isupro.jsp, it pushes me to /login.jspx. I
login with the username/password(database has an encrypted sha256
value of the password and spring does the magic of sha-ing the
password for comparison.
A nice tutorial (for others to read is here).
http://www.packtpub.com/article/spring-security-configuring-secure-passwords
This is what it looks like in GWT to pull that user up. (Straight from
Spring ROO).
/*
* identify the logged in user
*/
Receiver<UserInformationProxy> receiver = new
Receiver<UserInformationProxy>() {
public void onSuccess(UserInformationProxy
userInformationProxy) {
shell.getLoginWidget().setUserInformation(userInformationProxy);
}
};
requestFactory.userInformationRequest().getCurrentUserInformation(Window.Location.getHref()).fire(receiver);
That is it.
HTH
Ramon Buckland
On Nov 12, 1:32 pm, Patrick Hilsbos <
patrick.hils...@cloudsters.net>
wrote: