In Grails the URL like this
http://localhost:8080/MyApp/show/2
is there a way to hide or to encrypt the id part
/2
i need to do this to prevent users to access others data , for instance my ID is 3 , i could access other user's data by typing
/show/4
You can encode the url. If you replace the 2 with %32, the browser will still interpret it as the character 2. Here is a complete list of characters.
You can send POST request instead of GET - this is an easy way of hiding such a request parameters f.e. in server log files.
Or you can play with GRAILS codecs.
I would not hide the ID from the url. Why? because this would only mask the problem.
Consider having a class defined as :
class Post {
String title
String content
User user //you need this to keep track of the posts owner
//You could use your own custom class or the one used in spring security
...
}
If you use Spring Security Core, you would use a fucntion similar to:
def springSecurityService
#Secured(['ROLE_USER'])
def myFunction(Long id){
def postInstance = Post.read(id)
if(postInstance){
if (postInstance.user.id ==(long)springSecurityService.principal.id){
// springSecurityService?.principal?.id retrieves the id of the user in session
//... redirect to details of whatever you need
}else{
//... redirect because it is not the owner of the post
}
}
else{
//... Redirect or something
}
}
If you are using a simple session you would need to have a function like
def myFunction(Long id){
def postInstance = Post.read(id)
long userId = session["user_id"]
if(postInstance && userId > 0){
if (postInstance.user.id ==userId){
//... redirect to details of whatever you need
}else{
//... redirect because it is not the owner of the post
}
}
else{
//... Redirect or something
}
}
The logic is very similar. Still in my humble opinion you should use the spring Security plugin.
Related
I'm trying to redirect page on previous page when i click on currency menu. In this menu set selected currency in cookies and redirect to Request.UrlReferrer.ToString() so Request page automatic read cookies and apply currency.
Here is my code
public ActionResult Index(string currency)
{
HttpCookie cookie = new HttpCookie("Cookie");
cookie.Values["CODE"] = currency;
cookie.Values["sym"] = Currencies[currency];
cookie.Values["Name"] = CurrenciesName[currency];
string currencyname = GetCurrencySymbol(currency);
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
return Redirect(Request.UrlReferrer.ToString());
//return RedirectToRoute(Request.UrlReferrer.ToString());
}`
for example page1 have some item with amount in USD now user change currency then i send request to CurrencyController with above Action then return to same page1.
Above code working fine in all browsers but not working in IE 11.
give me some idea where I'm doing wrong.
Thanks
First and foremost, you should never rely on UrlReferrer. Its value comes from an HTTP header that is not guaranteed to be sent, and even if it is sent, it can be tampered with. By using it in the way you are, you're opening yourself up to CSRF and man-in-middle attacks.
The correct way to do something like this is to pass along the URL you want to return to. For example, if a user is on a URL like /foo/ and then clicks a link where you want to redirect them back to /foo/ afterwards, then the URL of the link should be something like: /bar/?returnUrl=/foo/.
Then, the action responding to /bar/ would do something like:
public ActionResult Bar(string returnUrl)
{
// do something
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
// redirect to default
}
The Url.IsLocalUrl check is to make sure that the return URL is a path on the current site, again, to prevent malicious attacks.
My problem is that i want to preview data on index view without saving data in database. For this purpose, I want to send the list of objects in params section of redirect. And on receiving action want to use that list of objects.But when i include as below
def preview(){
//some code
redirect action: "index", params:[planId:params.planId, beamsInfoList: beamsInfoList]
}
I want something like below to happen.
def index() {
//some code
try{
planInfo.beamInfo = (params.beamsInfoList==null)?planInfo.beamInfo:params.beamsInfoList //beamInfo is also list
//some code
Object[] obj = GRMUtils.calculateTotalBeamsPower(planInfo.beamInfo)
totalPlanPower = (Float)obj[0];
beamPowerMap= (Map<Integer, String>)obj[1];
AmMapUtility utility=new AmMapUtility()
output = utility.generateAMmapFromBeams(planInfo.beamInfo, GRMConstants.POWER_MAP_PAGE);
if(null==output){
flash.error = message(code: 'beammap.noinfoerror.message')
}
}catch(Exception e){
log.error "Excepton occured while loading Power Map", e
}
respond beams, model:[centerLong:output.getCenterLongitude(),centerLat:output.getCenterLatitude(),amMapImageProperty:output.getMapImages(),
amMapLinesProperty:output.getMapLines(), planId:params.planId, planInfo:planInfo, powersControlCarrier: powersControlCarrier, powersTrafficCarrier:powersTrafficCarrier,satPower: planInfo.satellite.satelliteMaxPower, totalPlanPower: totalPlanPower, gatewayPower: planInfo.gateway.gatewayAggregateEIRP,fesOutputPowerLimit:fesOutputPowerLimit, beamPowerMap: beamPowerMap,powerRangeColorMap:output.getReuseColorMap()]
}
It does not redirect to index method and not showing any errors. Both actions are in same controller. I have used flash, but its not helping either as value reflected on second request. I have tried session too, but i am getting error
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
on some DB fetch. I am stuck. I am new to grails and groovy. Please help.
Edit: i have found my list is large, that is why its not redirecting. Please help me with another alternative like how can i use request attribute if it is possible?
I think i have solved the problem. Its working now. All i need to do is to use the request setattribute as
request.beams = beams
And no need to pass the list in params of redirect, which i was earlier used to do. Instead of using redirect, i used forward as below:
request.beams = beams
forward action: "index", params:[planId:params.planId]
In my grails app I have customized the post authorization workflow by writing a custom auth success handler (in resources.groovy) as shown below.
authenticationSuccessHandler (MyAuthSuccessHandler) {
def conf = SpringSecurityUtils.securityConfig
requestCache = ref('requestCache')
defaultTargetUrl = conf.successHandler.defaultTargetUrl
alwaysUseDefaultTargetUrl = conf.successHandler.alwaysUseDefault
targetUrlParameter = conf.successHandler.targetUrlParameter
useReferer = conf.successHandler.useReferer
redirectStrategy = ref('redirectStrategy')
superAdminUrl = "/admin/processSuperAdminLogin"
adminUrl = "/admin/processAdminLogin"
userUrl = "/admin/processUserLogin"
}
As you can from the last three lines in the closure above, depending on the Role granted to the logging in User I am redirecting her to separate actions within the AdminController where a custom UserSessionBean is created and stored in the session.
It works fine for a regular login case which in my app is like so:
User comes to the app via either http://localhost:8080/my-app/ OR http://localhost:8080/my-app/login/auth
She enters her valid login id and password and proceeds.
The app internally accesses MyAuthSuccessHandler which redirects to AdminController considering the Role granted to this User.
The UserSessionBean is created and stored it in the session
User is taken to the app home page
I have also written a custom MyUserDetailsService by extending GormUserDetailsService which is correctly accessed in the above flow.
PROBLEM SCENARIO:
Consider a user directly accessing a protected resource (in this case the controller is secured with #Secured annotation) within the app.
User clicks http://localhost:8080/my-app/inbox/index
App redirects her to http://localhost:8080/my-app/login/auth
User enters her valid login id and password
User is taken to http://localhost:8080/my-app/inbox/index
The MyAuthSuccessHandler is skipped entirely in this process and hence my UserSessionBean is not created leading to errors upon further use in places where the UserSessionBean is accessed.
QUESTIONS:
In the problem scenario, does the app skip the MyAuthSuccessHandler because there is a target URL for it to redirect to upon login?
Can we force the process to always pass through MyAuthSuccessHandler even with the target URL present?
If the answer to 2 is no, is there an alternative as to how and where the UserSessionBean can still be created?
You can implement a customized eventListener to handle the post-login process, without disrupting the original user requested url.
In config.groovy, insert a config item:
grails.plugins.springsecurity.useSecurityEventListener = true
In you resources.groovy, add a bean like this:
import com.yourapp.auth.LoginEventListener
beans = {
loginEventListener(LoginEventListener)
}
And create a eventListener in src/groovy like this:
package com.yourapp.auth
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent
import org.springframework.web.context.request.RequestContextHolder as RCH
class LoginEventListener implements
ApplicationListener<InteractiveAuthenticationSuccessEvent> {
//deal with successful login
void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
User.withTransaction {
def user = User.findByUsername(event.authentication.principal.username)
def adminRole = Role.findByAuthority('ROLE_ADMIN')
def userRole = Role.findByAuthority('ROLE_USER')
def session = RCH.currentRequestAttributes().session //get httpSession
session.user = user
if(user.authorities.contains(adminRole)){
processAdminLogin()
}
else if(user.authorities.contains(userRole)){
processUserLogin()
}
}
}
private void processAdminLogin(){ //move admin/processAdminLogin here
.....
}
private void processUserLogin(){ //move admin/processUserLogin here
.....
}
}
Done.
1) Yes, because it is an "on-demand" log in.
2) Yes, you can set it to always use default. The spring security plugin has a setting for it "successHandler.alwaysUseDefault" change that to true it defaults to false.
Also if you need more details check out the spring docs look for the Setting a Default Post-Login Destination section.
3) If you want to still create the user session bean and then redirect to the original URL you have two options create the bean in an earlier filter or expose the needed data via a custom UserDetailsService. Personally I would go the route of a custom details service.
This is not one of the simple questions.. So let me explain it in detail...
The background:
In my grails application I have this mapping:
class UrlMappings {
static mappings = {
"/$storeId/$controller/$action?/$id?"
...
}
}
This means that all url's my application will process has preceding url parameter "storeId". All controllers will use this parameter to render content and perform other actions...
Also I have controller with annotation
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
class SomeController {
def index = {
// ...
}
}
Let's say user is trying to access this page:
/555/some/index
If this is unauthenticated user, security-plugin will redirect him to the
/login/auth
The issue is:
When spring-security will redirect to this page, user will see 404. This happens because login controller will handle only urls like
/555/login/auth
The question is:
What should I do to dynamically build this url?
p.s.
It turns out that:
There is config param for
spring-security, called
"auth.loginFormUrl". But this is just
static text. And I need to build this
url based on what url influenced this
redirection
The redirection is done (I'm not 100%
sure) in org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint#commence.
But how to override it?
Typically that's a static value, but it's called from LoginUrlAuthenticationEntryPoint.getLoginFormUrl(), so you could subclass that and do a dynamic calculation of the url in an overridden method. The plugin already subclasses it with org.codehaus.groovy.grails.plugins.springsecurity.AjaxAwareAuthenticationEntryPoint so you should extend that.
To register your implementation instead of the plugins, add a bean override in grails-app/conf/spring/resources.groovy:
import com.yourcompany.yourapp.YourAuthenticationEntryPoint
beans = {
authenticationEntryPoint(YourAuthenticationEntryPoint) {
loginFormUrl = '/login/auth' // has to be specified even though it's ignored
ajaxLoginFormUrl = '/login/authAjax'
portMapper = ref('portMapper')
portResolver = ref('portResolver')
}
}
You don't have direct access to the request in this method, but it's available in a thread-local - call org.codehaus.groovy.grails.plugins.springsecurity.SecurityRequestHolder.getRequest().
I'm using ASP.NET MVC and Forms Authentication on my application. Basically I use FormsAuthentication.SetAuthCookie to login and FormsAuthentication.SignOut to logout.
In the HttpContext.Current.User.Identity I have stored the user name but I need more info about the logged user. I don't want to store my entire User obj in the Session because it might be big and with much more infomation than I need.
Do you think it's a good idea to create like a class called LoggedUserInfo with only the attributes I need and then add it to the Session variable? Is this a good approach?
Or do you have better ideas?
I use this solution:
ASP.NET 2.0 Forms authentication - Keeping it customized yet simple
To summarize: I created my own IPrincipal implementation. It is stored in HttpContext.Current.Cache. If it is somehow lost, I have username from client side authorization cookie and can rebuild it. This solution doesn't rely on Session, which can be easily lost.
EDIT
If you want to use your principal in your controller and make it testable, you can do this:
private MyPrincipal _myPrincipal;
MyPrincipal MyPrincipal
{
get
{
if (_myPrincipal == null)
return (MyPrincipal)User;
return _myPrincipal;
}
set
{
_myPrincipal = value;
}
}
In your test, you will set object prepared for testing. Otherwise it will be taken from HttpContext. And now I started thinking, why do I use Ninject to do it?
Store it server side in the session.
Eg.
// Make this as light as possible and store only what you need
public class UserCedentials
{
public string Username { get; set; }
public string SomeOtherInfo { get; set; }
// etc...
}
Then when they sign in just do the following to save the users info:
// Should make typesafe accessors for your session objects but you will
// get the point from this example
Session["UserCredentials"] = new UserCredentials()
{ Username = "SomeUserName", SomeOtherInfo = "SomeMoreData" };
Then whenever you need it fetch it:
UserCredentials user = (UserCredentials)(Session["UserCredentials"]);
I have written a couple of question/answers regarding doing custom authorization in MVC:
How to implement authorization checks in ASP.NET MVC based on Session data?
How does the Authorize tag work? - Asp.net Mvc
I actually like to use a CustomPrincipal and CustomIdentity which I set in the logon action method like
if (!String.IsNullOrEmpty(username) && !String.IsNullOrEmpty(password) && _authService.IsValidLogin(username, password))
{
User objUser = _userService.GetUserByName(username);
if (objUser != null)
{
//** Construct the userdata string
string userData = objUser.RoleName + "|" + objUser.DistrictID + "|" + objUser.DistrictName + "|" + objUser.ID + "|" + objUser.DisplayName;
HttpCookie authCookie = FormsAuthentication.GetAuthCookie(username, rememberMe.GetValueOrDefault());
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);
FormsAuthenticationTicket newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, userData);
authCookie.Value = FormsAuthentication.Encrypt(newTicket);
Response.Cookies.Add(authCookie);
return RedirectToAction("Index", "Absence");
}
else
{
return RedirectToAction("LogOn", "Account");
}
}
else
{
return RedirectToAction("LogOn", "Account");
}
Then in the custom principal you can have methods that access specific information you passed in to the constructor like
((CustomIdentity)((CustomPrincipal)HttpContext.Current.User).Identity).DisplayName;
where the DisplayName property is declared in the CustomIdentity class.
Well you will have to store these somewhere. Two main possible places though:
The server
You can either put them into Session. I suggest you do create a separate class that will hold only data that you actually need to avoid of wasting too much memory. Or you can also store into Cache that can end up in having many DB calls when there are huge amounts of concurrent users.
The client
In this case if you can limit the amount of data with a separate class, to that and use whatever way to serialize it and send it to the client. Either in a cookie or in URI (if length permits and cookies are disabled)...
Outcome of these thoughts:
the main thing here would be to create a separate class if you gain much memory resources this way. So that's the first thing you should do.