Edit: I might have been unclear with my question. The authorization scheme is supposed to go off a page after the login page.
I am creating an Apex application with custom authentication, I successfully made the login page and am now able to set session item values. I made an apex application item called 'SESSION_USER_ROLE' and in my login authentication procedure I set the user role in the session state by using:
Apex_Util.Set_Session_State('SESSION_USER_ROLE', v_role);
After logging in with one of my user accounts and checking the session application items I can confirm that the item value and item name are properly set in the application items and session state.
However, when I try to access the value of the 'SESSION_USER_ROLE' item for an authorization scheme by using a PL/SQL function returning boolean I always seem to get 'false' even when I should be getting 'true'. This is the PL/SQL code I've been trying to use for authorization purpose:
DECLARE
v_role VARCHAR2(200);
v_auth boolean;
BEGIN
v_role := APEX_UTIL.FETCH_APP_ITEM('SESSION_USER_ROLE');
--This is the value of the SESSION_USER_ROLE for this specific user
if v_role = 'CEO' then
v_auth := true;
else
v_auth := false;
end if;
return v_auth;
END;
I don't understand what I'm doing wrong here. Is this not the correct way to retrieve the item value of SESSION_USER_ROLE?
Ensure the process that sets your application item where you refer to 'login authentication procedure' is referred to in the 'post-authentication procedure name' attribute of the current Authentication Scheme.
Alternatively, use the After Authentication computation point for application processes.
On new instance would be too early, before the person logs in.
Add some instrumentation using apex_debug.message, and run the process in debug mode.
For instance, you might like to log the value of v_role in the authentication process, and again after you fetch it in the Authorisation Scheme.
You may well be fetching it correctly, but does it have the value you expect? An alternative reference method is with bind variable syntax, :SESSION_USER_ROLE
On a side note, I've had more scalable success by defining authorisation schemes by privilege, not by business role.
Related
I'm trying to find a solution to create something similar to a server-side condition for pages. I want pages to be available depending on some global variables. I have created a function that returns a logical value in the database. How to implement it? I tried to use authorization schemes, but it doesn't work with parameters.
As far as I understood, value returned by that function decides whether someone is allowed to use certain page or not. You didn't explain what it exactly does, so I'll presume that it returns Boolean: TRUE (yes, allow page access) or FALSE (don't allow it), based on certain parameters such as :APP_USER.
If that's so, my suggestion would be to do what you already tried but failed for some reason.
navigate to Shared Components
go to Security - Authorization Schemes
create a new scheme, let's call it AS_ALLOW
set
scheme type = PL/SQL function returning Boolean
PL/SQL function body
return your_function(:APP_USER);
message displayed when scheme violated: "You aren't authorized to visit this page"
Now, back to page. Open its Security properties and put
AS_ALLOW into the "Authorization scheme"
That should do it; once the user runs the application, the function will return either TRUE or FALSE which will - in turn - allow (or not) that user's access to page that has the authorization scheme set.
I am trying to define a condition to my button in the home page that is of type pl/sql expression in order to hide this button, if the specific text is not submitted from other users. The expression that im trying to return is a text field from another page(login).Here is my expression
:P101_PASSWORD='xxxxxx'
Here xxxxxx is the condition to show the button but the button doesnt appear whenever i log in as xxxxxx.
I don't remember exactly, it could be one of two reasons: item P101_PASSWORD receives NULL value just after login process or value of item with type "Password" couldn't be used in SQL and PL/SQL(I'm not sure that this was described in documentation).
You can try to make experiment (I can't do until morning). I don't know, what you want to do, but if you ask user to enter password once again, use verification function to check.
If all you want to do is making the appearance of page items conditional on the name or group of the current user, querying the password field of your login page is most likely not the way you want to go (depending on your page processes, the session state of your page might get cleared after login. Also, if the user changes their password, you would need to update the display condition etc.).
The easiest way to handle this situation is probably to create a new group of users who should have access to the restricted information and functionality (call it PRIV_GROUP, for example). Next, define an authorization scheme of type 'PL/SQL Function Returning Boolean' with the following body:
BEGIN
RETURN APEX_UTIL.CURRENT_USER_IN_GROUP(p_group_name => 'PRIV_GROUP');
END;
Finally, set your authorization scheme as the button's display condition.
Edit:
In your case, since you are using custom authentication, I would suggest you create an application level item to store the name of the currently logged user. Go to Shared Components -> Application Items -> Create and create an item called LOGGED_USER.
Next, you need to create a post-authentication procedure:
In your DB, issue the following command:
CREATE OR REPLACE PROCEDURE post_authentication IS
BEGIN
apex_util.set_session_state('LOGGED_USER', upper(:P101_USER_NAME)); --Adapt to the name of your page item
END post_authentication;
To associate this procedure with your authentication scheme, go to Shared Components -> Authentication Schemes and edit your custom scheme. Under 'Post-Authentication Procedure Name', type "post_authentication" (without quotation marks).
If only user MANAGER should have access to the button, redefine your authorization (NOT authentication) scheme as follows:
BEGIN
IF :LOGGED_USER = 'MANAGER' THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;
At the end of an OAuth2 token exchange, I'm [typically] left with a JSON array of user data that I've un-marshalled into a struct (say, GoogleUser) with the fields I care about.
What is the sensible way of recording that data to my DB? Just call a CreateUser function from the callback handler, pass the struct and save it (the obvious way to me), after checking that the user doesn't already exist in the DB?
I assume I should then create a session token (i.e. session.Values["authenticated"] == true) in the callback handler, store that in a cookie (with a reasonable expiry date) and simply just check for if authenticated == true on any handler functions that expect a logged-in user? Or, for admin handlers: if admin_user == true. What are the risks here (if any) presuming I'm talking over HTTPS and using secure cookies?
Apologies for the basic questions: just trying to get a grip on "best practice" ways to log users in w/ OAuth.
With regards to your first question, It's usually recommended to do the check and insert in a single transaction. It depends on what DB you're using, but these are usually referred to as UPSERT statements. In PLSQL it looks a bit like this (modify to taste):
CREATE FUNCTION upsert_user(emailv character varying, saltv character varying, hashv character varying, date_createdv timestamp without time zone) RETURNS void
LANGUAGE plpgsql
AS $$;
BEGIN
LOOP
-- first try to update the key
UPDATE users SET (salt, hash) = (saltv, hashv) WHERE email = emailv;
IF found THEN
RETURN;
END IF;
-- not there, so try to insert the key
-- if someone else inserts the same key concurrently,
-- we could get a unique-key failure
BEGIN
INSERT INTO users(email, salt, hash, date_created) VALUES (emailv, saltv, hashv, date_createdv);
RETURN;
EXCEPTION WHEN unique_violation THEN
-- do nothing, and loop to try the UPDATE again
END;
END LOOP;
END;
$$;
In regards to your second question, usually Secure cookies over HTTPS is enough. I'd set the HttpOnly option, and usually the Path option as well.
HttpOnly means that the cookie can't be accessed by JS (only HTTP or HTTPS), and the Path option allows you to specify what path (in the URL) the cookie is valid for.
The Access Token in OAuth standard have a expiry. It's usually determined by authorization server. In your case I assume you are on authorization server side.
Read RFC 6750 for example:
Typically, a bearer token is returned to the client as part of anOAuth 2.0 [RFC6749] access token response. An example of such a response is:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"mF_9.B5f-4.1JqM",
"token_type":"Bearer",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA"
}
Also read concept of Access Token in RFC 6749:
The access token provides an abstraction layer, replacing different
authorization constructs (e.g., username and password) with a single
token understood by the resource server. This abstraction enables
issuing access tokens more restrictive than the authorization grant
used to obtain them, as well as removing the resource server's need
to understand a wide range of authentication methods.
So in your case, I don't think a "cookie" or "admin handler" is needed. You only have to generate Access Token & Refresh Token for each users logged in just like OAuth spec says, and store its expiry as well. You can also provide a hash method related with Access Token to make sure it's a legal request. For example, users use their access token to generate a signature with hash & salt method, send access token & signature to server to verify. Read Public Key Encryption for more details.
Furthermore, you don't need to save these tokens into your DB because they are all temporary resources. You can also save all user informations in memory and implement a cache layer to save these informations which truly important into DB periodically(which I'm currently using now) to lower DB pressure.
I am developing an ASP.Net MVC 3 Web Application. Within some of my Views I display tabular data to the user, and beside each record in the table there is an Edit link. When the user clicks this link it takes them to an edit page where they can edit and update the record.
My issue is that once the user clicks the edit link, the URL becomes something like this
http://www.mytestsite.com/myData/edit/3
The '3' is the ID of the record to be updated, however, there is nothing stopping the user from changing the '3' to another digit, and this then means they can edit potentially a record which does not belong to them.
Does anyone have a solution on how I can prevent this from happening?
Thanks for you help.
You need to introduce Authentication and Authorisation into your application. Here is one article of many out there on how to get started with this. You will additionally need to work out how to store logged on user identity and then how to attach this to the record when it was created in the first place. You must then validate, on the server, that the subsequent edit request is being made by the user who created the record in the first place (or by a user who has a role on your system which allows them to do this, such as an Administrator).
Even if the ID wasn't being displayed on the URL a malicious user could still manipulate the HTTP Request to pass an ID of their choice. In any secure system you should always, always, always validate that the currently logged on user genuinely has permission to carry out the requested action. You should never rely on what comes back from the browser to determine this (aside from the authentication context which is managed securely by the MVC framework. Usually).
I believe you should have the information about who have the edit permission on this purticular resource, in your tables. Ex : in your table you might have the "CreatedById" column where you store the ID of the user who created this record. Now in your edit action method, you check the "CreatedById" of the current Item is same as of the "UserId" of the Current user (you maye get this from the session, if you stored it there). Something like this.
public ActionResult Edit(int id)
{
int currentUserID=1; // TO DO : get this value from session or somewhere
ProductVieWModel product=myRepo.GetProduct(id);
if(product!=null)
{
if(product.CreatedById==currentUserID)
{
return View(product);
}
else
{
return View("NotAutherized");
}
}
return View("ProdcutNotFound");
}
You should try using the GUID data type as it helps in these kind of situations, and the user cannot easily guess the next value
I am working on a friend reference function, so I pass the user id through the url like this:
www.example.com?fid=22
I need to set this as a session or cookie with access to all modules in Drupal 6.
If i set the session it returns for the particular module. Setting the cookie is not working at all.
$user->new_property works only on the particular page where it is set, if I move to another page there is no new_property in $user variable object list.
If you want to save a variable in a users session, you can in Drupal (PHP) use the super global varaible $_SESSION.
$_SESSION['fid'] = $_GET['fid'];
The above code is an example of how this could be done.
Since you are getting the info from the URL the user can change it as his whim. So be careful what you use such data for and never trust it blindly. It could become anything, as the user always freely can alter the url any way he want.