grails spring security login page display - grails

I'm using the spring security plugin in a Grails app. There are two reasons why the login page gets displayed
The user navigated to it directly
The user tried to access a page that is only available to logged-in users
In the case of (2) only, I want to display a message like "you attempted to access a page that requires login", but in the GSP code of the login page I can't find a way to distinguish between (1) and (2), is this possible?

When you get redirected, Spring Security stores a SavedRequest in the session under the SPRING_SECURITY_SAVED_REQUEST_KEY key, so you could check for the existence of that in auth.gsp:
<g:if test='${session.SPRING_SECURITY_SAVED_REQUEST_KEY}'>
// display "you attempted to access a page that requires login"
</g:if>
<g:else>
// direct access to login
</g:else>

You could change the url of of the various spring security configurations to point to a controller, and then have it branch based on info in the session. In a 1.3.7 project is did something like
security {
authenticationFailureUrl = '/logout/doLogout'
afterLogoutUrl = '/logout/doLogout'
}
then had
class LogoutController {
def doLogout = {
def wasHere = session.getAttribute('some-attribute-you-set')
if (wasHere) render view: 'requirelogin'
else render view: 'normallogin'
}
}

Related

Grails : Spring Security Core how to login a user two different screens and failure screens

I have an application where I would like to create two different work flows for logging a user into an application using spring-security-core. One for customer, the other for an admin. So, to sum up there would be 2 different login screens. How can I achieve this? (auth/customer_login including where to redirect on failure, auth/admin_login including where to redirect on login failure)
Thanks in advance for any guidance.
Well, if you are using spring-security-core plugin, you don't have to create different login screens for the different type of access (admin & customer). You can/should always use the role-based authority to separate the usage. For example: ROLE_CUSTOMER won't see or will not be able to access the pages/features designed for admins and vice-versa.
Of course, there are annotation #Secured and various taglibs available to achieve the same.
But even if you wanted to provide the separate login screens then you can create two different views (or two actions) and use the session to redirect them if login fails.
I'm providing you a simple outline:
class LoginController {
// Action for admin login "/login/admin"
def admin() {
session.loginType = "ADMIN"
// render the login view from spring-security-core
}
def adminFailure() {
// do what you want after admin login failed
}
// Action for customer login "/login/customer"
def customer() {
session.loginType = "CUSTOMER"
// render the login view from spring-security-core
}
def customerFailure() {
// do what you want after customer login failed
}
// Acton when spring-security will redirect after any kind of failure
def loginFailed() {
if (session.loginType == "ADMIN") {
redirect action: "adminFailure"
} else if (session.loginType == "CUSTOMER") {
redirect action: "customerFailure"
}
}
}
and set the following in your application.groovy:
(check the Grails & plugin version)
grails.plugin.springsecurity.failureHandler.defaultFailureUrl = "/login/authFailed"

Setting username in application insights

I am new to application insights and have set it up using no custom events and I'm using all the defaults. The application is build on MVC 5. In the ApplicationInsights.config there's a comment saying:
"When implementing custom user tracking in your application, remove this telemetry initializer to ensure that the number of users is accurately reported to Application Insights."
We have a page where you are required to login so the default user logging isn't saying that much and we would much rather have the username being the unique identifier. Based on the comment it seems like this should be some kind of common modification and therefor easy to modify. When trying to google on "custom user tracking" I do not find anything interesting which seems a bit odd...
So how do I link the user in Application Insights to my username instead of going on some cookie which seems to be the default behaviour?
To link the user to your custom username, you can create the following telemetry initializer:
public class RealUserIDTelemetryInitializer:ITelemetryInitializer
{
public void Initialize(Microsoft.ApplicationInsights.Channel.ITelemetry telemetry)
{
// Replace this with your custom logic
if (DateTime.Now.Ticks % 2 > 0)
{
telemetry.Context.User.Id = "Ron Weasley";
}
else
{
telemetry.Context.User.Id = "Hermione Granger";
}
}
}
Then register this telemetry initializer in AI.config.
<TelemetryInitializers>
....
<Add Type="MyApp.RealUserIDTelemetryInitializer, MyApp" />
</TelemetryInitializers>

Grails/JQuery mobile view not displayed after login

Using Grails 2.4.3 and Spring Security plugin :spring-security-core:2.0-RC4
The default login view auth.gsp is working fine.
Added a user and can login, logout
and view secured pages.
Then I added JQuery mobile files to my layout and view.
I copied auth.gsp to /views/login/auth.gsp pastebin
My /views/layouts/main.gsp layout looks like this pastebin
My login page looks like this:
When I login with invalid credentials I get a blank page.
The source of the page before and after submit is exactly the same. pastebin
If I remove <script src="http://code.jquery.com/mobile/1.4.4/jquery.mobile-1.4.4.min.js"></script>
from main.gsp then I do see the output after submit.
Hope someone knows what I'm doing wrong.
UPDATE
In plugin/springsecurity/LoginController.groovy there is
def authfail() {
// ....
if (springSecurityService.isAjax(request)) {
render([error: msg] as JSON)
}
else {
flash.message = msg
redirect action: 'auth', params: params
}
}
If I change this to:
def authfail() {
// ...
flash.message = msg
redirect action: 'auth', params: params
}
then it is working and I see the login view again.
What still does not work is the redirection after successful login. Stil see a blank page.
Found that the answer on Spring Security Refresh Error in Grails jQuery Mobile app solves mine as well
Need to add data-ajax="false" and then it works.

Redirection in Grails Web-flow

I have question regarding redirection in Grails web-flow.
I am in a view state which will allow users to enter the answers for a question. On 2 wrong attempts I should be able to re-direct the user to view page from different controller. What i mean is
challengeQuestionOne{
onRender() {
//Display question
}
on('next') {BuildQuestion command ->
bindData(flow.recovery,command)
[return the model to flow]
if(command.hasErrors()) {
flow.command = command
return error()
}
if(check for status. If doesnot pass){
flash.message=message(code:'loginForm.account.locked', default: 'Please Contact Admin.')
redirect(controller : "login",action: "login")//how to redirect from here to diff controller
}
if (//compare answer entered) {
}
else{
//set status not active
}
}.to("challengeQuestionTwo")
on(Exception).to("error")
on('cancel').to('finish')
}
I have tried to redirect from onRender . It was redirecting to the page. But how do I display the error msg on the redirected page. How can i forward the error message from one controller to other??
Ivo Houbrechts wrote an excelent tutorial about grails webflow:
Webflow defines its own flash scope. Although it has the same semantics as the standard grails flash scope (the main purpose is to store objects only until after the next request), it is a different scope. This means that objects stored in webflow's flash scope are not visible in standard grails actions.
import org.springframework.web.context.request.RequestContextHolder
....
RequestContextHolder.currentRequestAttributes().flashScope.message = "YourMessage"
You can read more here:
http://livesnippets.cloudfoundry.com/docs/guide/
Flash scope will not work in this case as expected.
Try to use another approach to show error. E.g. you can pass parameters with redirect. Or you can throw some exception and check it on rendered page as follow:
<g:if test="${flowExecutionException}">
<div class="error"><g:message code="loginForm.account.locked"/></div>
</g:if>

How to use a shiro native session in a grails web application?

Currently, I am using the default HttpSession object in both controllers and gsp pages:
In controllers:
...
session.mykey = anObject; // adding an object to session
...
if (session.otherkey) { // performing some checking
In GSPs:
...
<g:if test="${session.mykey}">
...
I'd like to have a "remember me" functionality. Shiro has already it built in. However, as far as I understood, in order to do it I have to use the shiro native session mode (in Config.groovy: security.shiro.session.mode="native"). By default, it persists the session state, so objects will remain in the session as far as the cookie expires or the user logs off.
Is my understanding right?
Then i will have to change my controllers to this:
def shiroSession = SecurityUtils.subject.session
shiroSession.setAttribute("mykey",anObject)
....
if (shiroSession.getAttribute("otherkey") ){
And my views to this:
<g:if test="${SecurityUtils.subject.session.getAttribute('mykey')}">
So, my questions are:
Is that right?
Can't I just use the previous way to access the session?
Do I have to turn off the default http session in some configuration?
I gave up keeping objects in the session persistently (until cookie expires). Here is what i did:
In the login method in the controller:
if (! session.currentProfile){
Subject currentUser = SecurityUtils.getSubject()
if (currentUser.isRemembered()){
boolean success = configureSession(session, currentUser.getPrincipal())
if (success){
...
}
}
....
}
The first "if" checks whether the session has the object i need.
The configureSession method puts in the session all information I need.

Resources