I'm using Grails 3.2.4 and am attempting to use the email property of my User class as the username for registration.
So far, I've managed to get Spring Security Core to use the email as the username using the configuration setting below:
grails.plugin.springsecurity.userLookup.usernamePropertyName='email'
However, the registration functionality doesn't seem to take this into account and won't let me register a new user using only an email and password.
I've made a few attempts at overriding the RegisterController but I continue to experience different errors regarding null usernames.
It seems like I must be missing something very simple. Any help / direction is greatly appreciated.
It appears that in version spring-security-ui-3.0.0.M2 the username property might not be override-able.
String paramNameToPropertyName(String paramName, String controllerName) {
// Properties in the ACL classes and RegistrationCode aren't currently
// configurable, and the PersistentLogin class is generated but its
// properties also aren't configurable. Since this method is only by
// the controllers to be able to hard-code param names and lookup the
// actual domain class property name we can short-circuit the logic here.
// Additionally there's no need to support nested properties (e.g.
// 'aclClass.className' for AclObjectIdentity search) since those are
// not used in GSP for classes with configurable properties.
if (!paramName) {
return paramName
}
Class<?> clazz = domainClassesByControllerName[controllerName]
String name
if (clazz) {
String key = paramName
if (paramName.endsWith('.id')) {
key = paramName[0..-4]
}
name = classMappings[clazz][key]
}
name ?: paramName
}
PS I'm getting around this now by doing something like this in my user domain class:
static transients = ["migrating"]]
String username = null
public void setEmail(String email) {
this.email = email
this.username = email
}
Related
I have an AuthToken domain model. It accepts an token_string which is a JWT token.
class AuthToken {
String token_string
}
After initializing the AuthToken via new AuthToken(token_string: '...'), I would like to parse the token, and set properties on the class appropriately. For example expiration should be set based on the token.
If the token is invalid for whatever reason, I'd like to invalidate the AuthToken (i.e. token.validate() should be false).
How can I accomplish this with Grails / GORM?
I recommend adding a static factory method to parse the token String and return a AuthToken. Since you're dealing with a domain class, I'd avoid adding the constructor AuthToken(String tokenString) because then the default Map-based constructor will be deleted. You probably do not want that (and neither does GORM).
class AuthToken {
String token_string
String someProperty
static AuthToken parse(String token_string) {
new AuthToken(token_string: token_string).with {
someProperty = token_string.reverse() // an example
return delegate
}
}
}
def token = AuthToken.parse(aTokenString)
I am using the latest spring security 4 version and it introduces a new feature to use the logged in user details directly in the query method using expression language. Here is my spring data repository code:
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select username from User u where u.username = ?#{ principal?.username }")
User findByUsername(String username);
}
In the above code, I have an entity User as below:
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "password", nullable = false)
#NotNull
private String password;
#Column(name = "enabled", nullable = false)
#NotNull
private Boolean enabled;
#Column(name = "role", nullable = false)
#Enumerated(EnumType.STRING)
private Role role;
//getters and setters
Also I have this entry for enabling this feature:
#Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
When I run the application, I get the error:
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Authentication object cannot be null; nested exception is java.lang.IllegalArgumentException: Authentication object cannot be null
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:381)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:223)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417)
Caused by: java.lang.IllegalArgumentException: Authentication object cannot be null
at org.springframework.security.access.expression.SecurityExpressionRoot.<init>(SecurityExpressionRoot.java:46)
at org.springframework.security.data.repository.query.SecurityEvaluationContextExtension$1.<init>(SecurityEvaluationContextExtension.java:113)
at org.springframework.security.data.repository.query.SecurityEvaluationContextExtension.getRootObject(SecurityEvaluationContextExtension.java:113)
at org.springframework.data.repository.query.ExtensionAwareEvaluationContextProvider$EvaluationContextExtensionAdapter.<init>(ExtensionAwareEvaluationContextProvider.java:463)
at org.springframework.data.repository.query.ExtensionAwareEvaluationContextProvider.toAdapters(ExtensionAwareEvaluationContextProvider.java:210)
at org.springframework.data.repository.query.ExtensionAwareEvaluationContextProvider.access$000(ExtensionAwareEvaluationContextProvider.java:58)
What could be the issue. Here I am posting to check if there is any issue in using the query method. Can i use like principal.username, is that correct?
Update: When I removed the #Query from repository it works fine. That means its problem with the new spring security 4 using principal.username. Is there anything wrong in this expression?
#Query("select username from User u where u.username = ?#{ principal?.username }")
Pls try this custom class :-
class SecurityEvaluationContextExtension extends EvaluationContextExtensionSupport {
#Override
public String getExtensionId() {
return "Security";
}
#Override
public SecurityExpressionRoot getRootObject() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return new SecurityExpressionRoot(authentication){};
}
}
Not sure whether you have solved the issue in the meantime, but I noticed that your query should look like:
select u from User u where u.username = ?#{ principal }
assuming your principal object is the plain username String.
If you created your own SecurityEvaluationContextExtension class, and did not implement getAuthentication() method, you might be getting this exception.
In this link, you can see original SecurityEvaluationContextExtension.java file, that implements all necessary methods.
So, you don't need to implement this class on your own. Instead, you can add below dependency to your pom file to have the original one;
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-data -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-data</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
If you are using any other dependency manager rather than maven, you can goto related maven repo and get the definition that you want.
I hope this helps.
Is there any way to define the users that can use my application in a list in Config.groovy? This will be using Grails 2.2.3 and the latest versions of Spring Security Core and Spring Security LDAP.
We use Active Directory for authentication, and only 2 or 3 people will use this little application, so it doesn't seem worthy of making an AD Group for just this app. It would be simpler to define a list, and any time there is a new hire instead of adding them to the AD group all I have to do is add their name to the external Grails config.
I would like to do something like the following:
SomeController.groovy
#Secured("authentication.name in grailsApplication.config.my.app.usersList")
class SomeController {
}
Then in Config.groovy put this code:
my.app.usersList = ['Bill', 'Tom', 'Rick']
Is this possible? If so, is this a terrible idea? Thanks a lot.
That seems really silly. Why not have the list of users in a table? Then you can add/remove from that table without have to modify the application.
I currently do this and in my UserDetailsContextMapper I make sure the username already exists in the Users table.
You need a custom authenticator that will try to access your Active Directory and if authenticated, will look into Grails properties to check if the username is allowed to login.
This is the class that I use. I changed the code to validate the config:
class ActiveDirectoryAuthenticator {
private DefaultSpringSecurityContextSource contextFactory
private String principalSuffix = ""
def grailsApplication
public DirContextOperations authenticate(Authentication authentication) {
// Grab the username and password out of the authentication object.
String principal = authentication.getName() + "#" + principalSuffix
String password = ""
if (authentication.getCredentials() != null) {
password = authentication.getCredentials().toString()
}
// If we have a valid username and password, try to authenticate.
if (!("".equals(principal.trim())) && !("".equals(password.trim()))) {
try {
String provider = contextFactory.getUrls()[0]
Hashtable authEnv = new Hashtable(11)
authEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory")
authEnv.put(Context.PROVIDER_URL, provider)
authEnv.put(Context.SECURITY_AUTHENTICATION, "simple")
authEnv.put(Context.SECURITY_PRINCIPAL, principal)
authEnv.put(Context.SECURITY_CREDENTIALS, password)
javax.naming.directory.DirContext authContext = new InitialDirContext(authEnv)
//here validate the user against your config.
if(!authentication.getName() in grailsApplication.config.adUsersAllowed) {
throw new BadCredentialsException("User not allowed.")
}
DirContextOperations authAdapter = new DirContextAdapter()
authAdapter.addAttributeValue("ldapContext", authContext)
return authAdapter
} catch ( NamingException ex ) {
throw new BadCredentialsException(ex.message)
}
} else {
throw new BadCredentialsException("Incorrect username or password")
}
}
public DefaultSpringSecurityContextSource getContextFactory() {
return contextFactory
}
/**
* Set the context factory to use for generating a new LDAP context.
*
* #param contextFactory
*/
public void setContextFactory(DefaultSpringSecurityContextSource contextFactory) {
this.contextFactory = contextFactory
}
public String getPrincipalSuffix() {
return principalSuffix
}
/**
* Set the string to be prepended to all principal names prior to attempting authentication
* against the LDAP server. (For example, if the Active Directory wants the domain-name-plus
* backslash prepended, use this.)
*
* #param principalPrefix
*/
public void setPrincipalSuffix(String principalSuffix) {
if (principalSuffix != null) {
this.principalSuffix = principalSuffix
} else {
this.principalSuffix = ""
}
}
}
Declare it as your ldapAuthenticator in resources.groovy:
ldapAuthenticator(ActiveDirectoryAuthenticator) {
contextFactory = ref('contextSource')
principalSuffix = 'domain.local' //your domain suffix
grailsApplication = ref('grailsApplication')
}
The downside is that you need to restart your context when you change config.groovy
In your controllers just use #Secured('IS_AUTHENTICATED_FULLY')
I do not think you can do that because annotations are resolved at compile time and not in runtime. Config properties will be read during the application runtime so you I fear you have to end up doing:
#Secured(["authentication.name in ['Bill', 'Tom', 'Rick']"])
class SomeController {
}
If I remember correctly the #Secured annotation cannot be used for other things than comparing roles. But you should be able to do this with spring securities #PreAuthorize and #PostAuthorize annotations. When using grails the easiest way to setup these annotations is installing the spring security ACL plugin.
Within #PreAuthorize and #PostAuthorize you can use SPEL expressions which are more flexible. Unfortunatelly SPEL does not provide an in operator. However you can delegate the security check to a service:
#PreAuthorize('#securityService.canAccess(authentication)')
public void test() {
println "test?"
}
With the # symbol you can reference other beans like services within expression. Here the method securityService.canAccess() is called to evaluate if the logged in user can access this method.
To use this you have to configure a BeanResolver. I wrote some more details about configuring a BeanResolver here.
Within securityService you can now do:
class SecurityService {
def grailsApplication
public boolean canAccess(Authentication auth) {
return grailsApplication.config.myList.contains(auth.name)
}
}
In general I would not recommend to use a configuration value for validating the user in security checks. The groovy configuration will be compiled so you cannot easily add a new user without redeploying your application.
I'm doing some simple validation inside my Controller I know this would better placed inside something like a service layer but for this I want to keep it inside the Controller
The idea is to check that a valid url is being entered into a url field to display an image, e.g. http://domain.com/myawesomeimage.png would be valid and http://domain.com/ would not be valid.
// ValidateInt has a default value of 0
int ValidateInt = 0;
// If the url entered (if one at all) does not have correct extension then increment the ValidateInt
if (!ArticleToEdit.image.Contains(".jpg"))
ValidateInt++;
if (!ArticleToEdit.image.Contains(".jpeg"))
ValidateInt++;
if (!ArticleToEdit.image.Contains(".png"))
ValidateInt++;
if (!ArticleToEdit.image.Contains(".gif"))
ValidateInt++;
if (!ArticleToEdit.image.Contains(".bmp"))
ValidateInt++;
// if ValidateInt is bigger than 0 then the url is invalid
if (ValidateInt > 0)
ModelState.AddModelError("Image", "Please enter a valid URL.");
EDITED CODE
The problem with your code
Your code is invalid, because your model state will always have at least 4 errors. Even though the URL would be correct. Your code requires that your URL must have all extensions which is of course incorrect. It can only have one. At most.
The solution
Use DataAnnotations instead and use regular expression validator. You're obviously already using some application model class called ArticleToCreate. You'll have to put data annotations attribute on the image property (one more observation: keey property names with Pascal casing so it's the same as .net):
public class ArticleToCreate
{
[RegularExpression(#"...")] // add regular expression that fulfils your requirements
public string Image { get; set; }
...
}
Then it all depends how complicated your regular expression is. The easiest one for your needs could be just that it starts with an http:// and end with the correct extension:
^http:\/\/.+\.(?:png|jpe?g|gif|bmp)$
And if you're directly providing your class instance to controller action it will get automatically validated for you without any additional code. This way you won't be able to forget to validate your objects manually.
Consider this controller action that automatically validates your model class object instance by validators defined on it (as per validator definition I've written above):
public ActionResult Create(ArticleToCreate data)
{
if (!this.ModelState.IsValid)
{
// handle invalid object
}
// handle valid object
}
This way your actions will focus on the processing part which is their main objective instead of focusing on too many aspects of your business process like validation for instance.
Shorter code = simpler code = easier to maintain = less bugs = less work = happy clients
Why not create custom ValidationAttributes (from DataAnnotations) and allow the Validation Engine do the work for you rather than worrying about where to put your logic?
I'm guessing it would look something like:
[AttributeUsage(AttributeTargets.Property |
AttributeTargets.Field, AllowMultiple = false)]
public class ValidImageUrlAttribute : ValidationAttribute
{
public string ErrorMessage { get; set; }
public override bool IsValid(object value)
{
var url = value as string;
if(!url.Contains(".jpg") || !url.Contains(".jpeg")
|| !url.Contains(".gif") || !url.Contains(".bmp")
|| !url.Contains(".png"))
{
return false;
}
return true;
}
public override string FormatErrorMessage(string name)
{
return ErrorMessage ?? base.FormatErrorMessage(name);
}
}
And then you could decorate your Model:
[Required(ErrorMessage = "Image URL is required.")]
[ValidImageUrl(ErrorMessage = "Valid Image URL is required.")]
public string ImageUrl { get; set; }
changed if (validate1 > 0) and it works fine :)
I'm writing an ASP.NET MVC application which will provide user registration functionality but i am not sure which part of the application (e.g. User Domain model object, Controller, ViewModelMappers) should be responsible for hashing the user's password. I have a registration page that uses a strongly typed ViewModel and a Register action in my UserController as shown:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Register(UserRegisterViewModel userRegisterViewModel)
{
var user = userViewModelMapper.Map(userRegisterViewModel);
INotification validationResult = user.ValidateForRegistration(userRepository);
if (!validationResult.HasErrors)
{
user.HashPassword();
userRepository.AddOrUpdate(user); // i'm using NHibernate
return View("RegistrationAcknowledgement");
}
foreach (IError error in validationResult.Errors)
ModelState.AddModelError(error.Property, error.Message);
ViewData["country"] = new SelectList(countryRepository.GetAll(), "Code", "Name", userRegisterViewModel.Country);
return View("RegistrationForm", userRegisterViewModel);
}
User objects are composed in part by LoginDetail objects as shown and to avoid exposing the internals of the User object beyond what is absolutely required the Password Property is read-only. So i cannot for example do user.LoginDetails.Password = hashedandSaltedPassword;
namespace XXXX.Core.Model
{
public class User
{
private LoginDetails loginDetails;
public virtual LoginDetails LoginDetails
{
get { return loginDetails; }
private set { loginDetails = value; }
}
public virtual void AssignLoginDetails(LoginDetails loginDetails)
{
this.loginDetails = loginDetails;
}
public virtual void HashPassword()
{
IHashGenerator hashGenerator = new HashGenerator(new SaltGenerator());
IHashResult hashResult = hashGenerator.GenerateHash(loginDetails.Password, HashAlgoritm.SHA512);
loginDetails.Password = String.Concat(hashResult.HashValue, hashResult.Salt);
}
}
}
namespace XXXX.Core.Model
{
public class LoginDetails
{
private string username;
private string password;
private string confirmPassword;
private string passwordReminder;
private bool changePassword;
// Properties
#region Constructors
...
public LoginDetails(string username, string password, string confirmPassword, string passwordReminder, bool changePassword)
{
this.username = username;
this.password = password;
this.confirmPassword = confirmPassword;
this.passwordReminder = passwordReminder;
this.changePassword = changePassword;
}
}
}
Currently the responsibility for hashing the password is owned the User (by means of the HashPassword method) but
1. Is this a correct responsibility for the User to have (within the context of DDD and Single Responsibility principle)
2. If not, where should this operation reside?
3. If so, should it be called from the controller as i am doing?
Thanks
Without reading your code, I would argue hashing the password should be done in the model so it can be reused outside of the MVC framework. This tends to be true in all MVC frameworks that are implemented in languages general enough to be useful outside of the web.
Let's take a step back and look at the broader picture: when do we want to take a password in clear and hash it?
when the user is creating or
changing their password, and we need
to store it
when the user is logging in, and we
need to compare the entered
password with the the stored one
Currently your implementation addresses only the first instance. So you need a method which accepts a clear password and returns a hashed one.
As for where that method should go ...
The Single Responsibility Principle does not mean that a class does literally one thing. It means that the class handles only things which are clearly within its remit.
So, consider is the relationship between User and hashed password. Can you have a User wthout a hashed password? Will you ever want to work with a hashed password without its User? Do you have other objects which have a hashed password besides User? If the answer to those questions is "No" then I would argue that the password hashing method clearly belongs to the User class, and indeed increases its cohesiveness.