Grails redirect redirects to invalid location - grails

I'm running my app in development environment.
Using this simple controller:
class MyController {
def index() {
redirect uri: '/'
}
}
I'm getting redirected to http://localhost:8080/[:]/ location for some reason.
$appName seems good inside Config.groovy. grails.serverURL looks also OK.
What's the problem?
UPDATE 1
I'm using grails 2.2.4
UPDATE 2
The problem is with invalid grails.serverURL value. When I'm debugging the app, it has a correct value inside Config.groovy. When I'm printing out this value from servlet method it's set to http://localhost:8080/[:]/ for some reason. I'm using Spring Security Core 1.2.7.3 and Spring Security UI 0.2, I think that for some reason grails.serverURL is overwritted inside this plugin.
How to fix it?

The answer was simple. I've included MyConfig.groovy inside Config.groovy like this:
grails.config.locations = [ "classpath:${appName}-config.properties",
"classpath:${appName}-config.groovy",
MyConfig,
"file:${userHome}/.grails/${appName}-config.properties",
"file:${userHome}/.grails/${appName}-config.groovy"]
there was also environments.production, environments.development and environments.test sections however, $appName is undefined there. I've removed setting of grails.serverURL from MyConfig.groovy and its worked now.

Related

After Grails 4 upgrade my URL Mappings and interceptors no longer work

I am trying to upgrade from 3.3.x to 4.0.13 but after doing so my URL mappings and interceptors no longer work. I believe there is a root issue that is the same between the 2 because of debug statements I have in my interceptor make it appear someone in the underlying grails mappings is broken.
URLMappings
static mappings = {
"/api/admin/$controller/$action?/$id?(.$format)?"{
namespace = "admin"
constraints {
// apply constraints here
}
}
"/"(redirect: "/app/")
"/app"(uri: "/index.html")
"/app/**"(uri: "/index.html")
"500"(view:'/error')
"404"(redirect: "/app/")
}
UserController
class UserController extends AdminController {
static namespace = "admin";
def save(UserCommand cmd) {
[...]
}
}
LoginInterceptor
class LoginInterceptor {
LoginInterceptor() {
matchAll()
.excludes(controller: ~/(login|logout|publicLookupSvc)/);
}
boolean before() {
println(controllerNamespace);
println(controllerName);
println(actionName);
println(request.requestURI);
true
}
}
So the underlying issue I am referring to is that my debug statments in 4.0.13 print null whereas in 3.3.x they actually print values
So if I visit the URL: http://localhost:8081/raa/api/admin/user/save
In 3.3
println(controllerNamespace); -> admin
println(controllerName); -> user
println(actionName); -> save
println(request.requestURI); -> /raa/api/admin/user/save
In 4.0.13
println(controllerNamespace); -> null
println(controllerName); -> null
println(actionName); -> null
println(request.requestURI); -> /raa/api/admin/user/save
Along with the error stacktrace
2022-04-20 13:15:33.303 ERROR --- [nio-8081-exec-3] o.g.web.errors.GrailsExceptionResolver : IllegalArgumentException occurred when processing request: [GET] /raa/api/admin/user/save
URL mapping must either provide redirect information, a controller or a view name to map to!. Stacktrace follows:
java.lang.IllegalArgumentException: URL mapping must either provide redirect information, a controller or a view name to map to!
at org.springframework.util.Assert.isTrue(Assert.java:118)
at org.grails.web.mapping.DefaultUrlMappingInfo.<init>(DefaultUrlMappingInfo.java:105)
at org.grails.web.mapping.DefaultUrlMappingInfo.<init>(DefaultUrlMappingInfo.java:99)
at org.grails.web.mapping.ResponseCodeUrlMapping.match(ResponseCodeUrlMapping.java:136)
[...]
Consequently, since all the attributes are null regarding where my request is suposed to be routed, the matchAll() does not work either. When I vist my login/logout/publicLookupSvc controllers the interceptor still gets hit even though it should be skipped.
I feel like once I figure out why those mapping paramters are not being populated correctly everything will fall into place. I just can't figure out why thats happening.
Grails 4.0.13
JDK 11.0.13
Gradle 5.0
The way you delcared your contextPath in Grails 4.x has changed and this was causing all my URL to be incorrect. After fixing this everything worked as expected.
Grails 3.x
server:
contextPath: '/myapp'
Grails 4.x+
server:
servlet:
contextPath: '/myapp'

log4j2 monitorInterval using spring cloud config server

I'm trying to read the log4j2 configuration from config server during application startup.
bootstrap.yml
spring:
application:
name: loggingApp
cloud:
config:
uri: http://localhost:8888
logging:
config: http://localhost:8888/loggingApp/raw/master/loggingApp-log4j2-DEV.xml
The application seems to get the configuration properly during start up as I see the appropriate log levels. However, the automatic configuration doesn't seem to work. When I change the log level of the loggers, looks like it didn't read the updated config from config server after the monitorInterval has passed. I've set the monitorInterval to 10 seconds. As per the documentation the minimum interval should be 5 seconds. If I point to a file on local drive, instead of the config server url, it is working fine. I tried using -Dlog4j.configurationFile as jvm arg as well as spring configuration logging.config to see if one of those work, but none worked.
https://logging.apache.org/log4j/2.x/manual/configuration.html#AutomaticReconfiguration
https://logging.apache.org/log4j/2.x/log4j-spring-cloud-config/log4j-spring-cloud-config-client/index.html
I'm using spring-boot 2.2.5.RELEASE, log4j2 2.13.1 and spring-cloud Hoxton.SR3 versions.
This is how the git repo looks like where config files are being read from
I too tried the same and it did not work. It seems the <Configuration monitorInternal="10"> property would only have worked if we use log4j.configurationFile property to load the log4j2 config file as mentioned in Apache's Log4j Spring Cloud Configuration Guide .
I used the spring actuator refresh approach to accomplish this task. However this does not reload the configs on its own. So there is work around to meet the required ends. Create a scheduler in your spring application that hits the actuator refresh url on specified intervals as below
#Component
#EnableScheduling
public class RefreshScheduler {
#Autowired
private RestTemplate restTemplate;
#Scheduled(fixedRate = 60000)
private void postRefreshEndPoint() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(headers);
restTemplate.postForEntity("http://localhost:8080/actuator/refresh", entity, String.class);
}
}
This is surely a very dirty way of somehow achieving the required functionality. It works though :)
As a side note : Isn't it better to not have automatic refresh? My argument would be : It's possible developers by mistake ( or just for fun ) do changes to the configs in GIT. And this will lead to a change in the live application in prodcution.
However if we have the actuator refresh URL as mandatory for refreshing the spring context, this can be stopped. Only authorized memebers from the production/operations team would have access to this refresh url and they can decide whether to actually refresh the production spring beans when a commit on GIT has been done.

grails 4 sessionRegistry empty

Upgrading to grails 4, sessionRegistry.getAllPrincipal() is always empty.
The original spring bean in resources.groovy were
sessionRegistry(SessionRegistryImpl)
concurrentSessionFilter(ConcurrentSessionFilter){
sessionRegistry = sessionRegistry
expiredUrl = '/login'
}
As this was no longer working I tried updating resources.groovy to
sessionRegistry(SessionRegistryImpl)
registerSessionAuthenticationStrategy(RegisterSessionAuthenticationStrategy, ref(sessionRegistry))
sessionFixationProtectionStrategy(SessionFixationProtectionStrategy)
concurrentSessionControlAuthenticationStrategy(ConcurrentSessionControlAuthenticationStrategy, ref(sessionRegistry)){
maximumSessions=1
exceptionIfMaximumExceeded=true
}
compositeSessionAuthenticationStrategy(CompositeSessionAuthenticationStrategy,
[ref(registerSessionAuthenticationStrategy),ref(sessionFixationProtectionStrategy),ref(concurrentSessionControlAuthenticationStrategy)])
All of those beans are from the org.springframework.security.web.authentication.session package.
I've added names to grails.plugin.springsecurity.providerNames as well
The DaoAuthenticationProvider is extended by a custom auth provider. Login and logout works fine, but the principals never get registered in the upgraded app. Do I need register them manually (sessionRegistry.registerNewSession())?
There are old answers that say to use grails install-templates and then edit the web.xml in src/templates/war. However in grails 4, install-templates didn't generate war/web.xml
I tried adding it a /WEB-INF/web.xml, but still no luck.
I think you're missing the sessionAuthenticationStragegy bean definition, try removing the compositeSessionAuthenticationStrategy line and replace it with:
sessionAuthenticationStrategy(CompositeSessionAuthenticationStrategy, [ref('concurrentSessionControlAuthenticationStrategy'), ref('sessionFixationProtectionStrategy'), ref('registerSessionAuthenticationStrategy')])
This is the only difference I see between your code and mine, which is working with Grails 4.

Externalized Grails 3 Spring Security Config

I am working on externalizing the .YML file in Grails 3.x. The code to make this work, is as follows:
In my Application.groovy, I am implementing the setEnviroment method form the EnvironmentAware interface.
#Override
void setEnvironment(Environment environment) {
try {
String configPath = System.properties["local.config.location"]
def ymlConfig = new File(configPath)
Resource resourceConfig = new FileSystemResource(ymlConfig)
YamlPropertiesFactoryBean ypfb = new YamlPropertiesFactoryBean()
ypfb.setResources(resourceConfig)
ypfb.afterPropertiesSet()
Properties properties = ypfb.getObject()
environment.propertySources.addFirst(new PropertiesPropertySource("local.config.location", properties))
} catch (Exception e) {
log.error("unable to load the external configuration file", e)
}
}
I have edited the bootRun task in the build to this:
bootRun {
jvmArgs = ['-Dlocal.config.location=external-config.yml']
}
When printing out the values in the setEnvironment method, the properties are indeed being read and added from the loaded object.
Now, for the fun part. When I add this code to my original application.yml file:
---
grails:
plugin:
springsecurity:
securityConfigType: 'InterceptUrlMap'
interceptUrlMap: [
{pattern: '/**', access: ['permitAll']}
]
providerNames: ['ldapAuthProvider', 'anonymousAuthenticationProvider']
ldap:
context:
managerDn: 'uid=admin,ou=system'
managerPassword: 'secret'
server: 'ldap://localhost:10389'
authorities:
groupSearchBase: 'ou=Groups,dc=aye,dc=com'
retreiveGroupRoles: true
retreiveDatabaseRoles: false
groupSearchFilter: 'member={0}'
search:
base: 'ou=Users,dc=aye,dc=com'
password:
algoritham: 'SHA-256'
---
Everything works just fine. When I cut and paste it out into the external yml file, I get this beautiful error in Firefox.
I can tell that the configuration is correct in the provided code, as I can add more roles and filters, and everything works just fine when in original application.yml file. It is only when reading from the external file does this fail. If I remove the security code from both .yml files, .ofc, my page looks strange but the firefox error disappears.
Has anyone got an idea as to why this can be the case?
One thing you can attempt to test if it will work, is rename your external-config.yml file to application.yml. I believe that the default name should be application, unless otherwise specified.
This article here shows a good example of its correct use
When you do that, try to read the properties in one of your classes, to make sure that the yml files are merging. You can read these properties using a command like this:
grailsApplication.config.getProperty("grails.plugin.springsecurity.securityConfigType")
Or, you can print out all of them, using the Holders utility
def config = Holders.config

Grails Spring Security Core Plugin

I am (finally) upgrading my Acegi plugin to Spring Security Core. At the same time, I am upgrading from Grails 1.3.7 to 2.0. My site was fully functional before, but now when I try to get to my default page (which is IS_AUTHENTICATED_ANONYMOUSLY) I am redirected to the auth action of my LoginController. This method was never invoked with Acegi, so I don't know what the problem is. Have I set up my configuration wrong or is there something else I need to be thinking about?
grails.plugins.springsecurity.securityConfigType = SecurityConfigType.InterceptUrlMap
grails.plugins.springsecurity.interceptUrlMap = [
'/blog/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/static/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/consensus/**':['IS_AUTHENTICATED_FULLY'],
'/login/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/signup/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/home/**':['IS_AUTHENTICATED_FULLY'],
'/test/**':['ROLE_ADMIN'],
'/admin/**':['ROLE_ADMIN'],
'/adminmanage/**':['ROLE_ADMIN'],
'/quartz/**':['ROLE_ADMIN'],
'/**/*.css':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/js/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/images/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/monitoring**':['ROLE_ADMIN'],
'/**':['IS_AUTHENTICATED_FULLY']
]
My UrlMappings.groovy is:
class UrlMappings {
static mappings = {
"/"(controller:"x", action:"y")
"/z/?"(controller:"x", action:"y")
"/$controller/$action?/$id?"
{
constraints {
// apply constraints here
}
}
"500"(view: '/error')
}
}
I have been reading through the documentation but am having some problems, so I am not sure if there is more relevant code one would need to see. If there is, please let me know and I will add it. Thanks.
Other options in my Config.groovy were incorrect and this caused the problem. Once I corrected them everything worked fine.
Despite it being called out in the documentation, I had security fields that were not prepended with grails.plugins.springsecurity This caused the engine not to recognize them, which for some reason resulted in the call to auth.
After remove openid plugin all requests redirects me to the login page! I don't know what to do... I've already remove everything related.

Resources