How to secure the segment passed to the controller in CI - security

I am trying to pass a segment to a controller. The url is like base_url/controller/function/seg1. I want to ensure that if the user try to enter the segment in the address bar, the controller would make sure there are not other words to be proceeded except the segment I want to pass.
For example, If the user tries to type base_url/main/function/(change this to other words) in address bar, the controller will filter the segment. I am not sure how to do it and would appreciate if someone can help me out.

Okay, so the best way to "secure" against such things would be to simply create a session at the time the user logs into your site with two values stored in that session;
1) Their database primary key id, and
2) a session item called 'logged_in'
At the time that your user would log into your site, you would store those two values like this;
$this->session->set_userdata('logged_in', true);
$this->session->set_userdata('user_id', $id);
Where $id is pulled from their user record during authentication.
Now that you have those in there, the next part would be that, in your controller, you would put an if statement in that checks if the user is logged in, as such;
function show($id) {
if($this->session->userdata('logged_in')) {
$posts = $this->Model_posts->get_user_posts($id);
}
}
Now, in your model, you would create a function for pulling the record that you want the user to be able to view based on their user_id. We'll say user posts for example.
function get_user_posts($user_id, $post_id) {
$sql = "SELECT * FROM posts WHERE user_id = ? AND id = ?";
$binds = array($user_id, $post_id);
$qry = $this->db->query($sql, $binds);
$result = array();
while($row = $qry->result_array()) {
array_push($result, $row);
}
return $result;
}
Now, when a logged in user or visitor tries to access records that don't belong to them, they will not retrieve any records because the select statement limits what's returned only to that user.

The structure you have there is
base_url/controller/action
So, your controller is already "filtering" it out because if you don't have a method/function in the controller (methods = actions) then your controller will trigger a 404 Page Not Found error. Of coarse, you could then handle your errors however you see fit, but from what you presented, the item you wish to filter is known as a controller action.
So for instance;
http://www.base_url.com/users/add
denotes that you wish to call the add (function) in the users controller.
If you want to pass the add action an argument, then you would do this as;
http://www.base_url.com/users/show/1
Where show would be a controller action and 1 would be the id of the user you wish to show.
I know it seems like I'm giving a basic intro to MVC methodologies, but like I said, the structure you showed plays out like I described.
Hope this helps.

Related

BreezeJS SaveChanges() security issue

I'm using BreezeJS and have a question regarding how data is saved. Here's my code and comments
[Authorize]
/*
* I want to point out the security hole here. Any Authorized user is able to pass to this method
* a saveBundle which will be saved to the DB. This saveBundle can contain anything, for any user,
* or any table.
*
* This cannot be stopped at the client level as this method can be called from Postman, curl, or whatever.
*
* The only way I can see to subvert this attack would be to examine the saveBundle and verify
* no data is being impacted that is not owned or related directly to the calling user.
*
* Brute force could be applied here because SaveResult contains Errors and impacted Entities.
*
*/
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _efContext.SaveChanges(saveBundle);
}
To limit access to a callers ability to retrieve data I first extract from the access_token the user_id and limit all my queries to include this in a where clause, making it somewhat impossible for a user to retrieve another users data.
But that would not stop a rogue user who had a valid access_token from calling SaveChanges() in a brute force loop with incremental object ids.
Am I way off on this one? Maybe I'm missing something.
Thanks for any help.
Mike
The JObject saveBundle that the client passes to the SaveChanges method is opaque and hard to use. The Breeze ContextProvider converts that to a map of entities and passes it to the BeforeSaveEntities method. BeforeSaveEntities is a method you would implement on your ContextProvider subclass, or in a delegate that you attach to the ContextProvider, e.g.:
var cp = new MyContextProvider();
cp.BeforeSaveEntitiesDelegate += MySaveValidator;
In your BeforeSaveEntities or delegate method, you would check to see if the entities can be saved by the current user. If you find an entity that shouldn't be saved, you can either remove it from the change set, or throw an error and abort the save:
protected override Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(
Dictionary<Type, List<EntityInfo>> saveMap)
{
var user = GetCurrentUser();
var entityErrors = new List<EFEntityError>();
foreach (Type type in saveMap.Keys)
{
foreach (EntityInfo entityInfo in saveMap[type])
{
if (!UserCanSave(entityInfo, user))
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Forbidden)
{ ReasonPhrase = "Not authorized to make these changes" });
}
}
}
return saveMap;
}
You will need to determine whether the user should be allowed to save a particular entity. This could be based on the role of the user and/or some other attribute, e.g. users in the Sales role can only save Client records that belong to their own SalesRegion.

Write the plugin when Selecting the lookup flied and according to filed selection Show/Hide Address filed in form.....?

We Have Contact Entities in contact Entitie one lookup filed company Name in that lookup having two values 1.Account and 2.Contact . When we are selecting contact show the address filed when we select account hide the address filed we needs to write the plugin to Execute that works. Kindly any one help me on the same.
Thanks!!
Rajesh Singh
First, if you need to make change on a form, you can't use plug-ins. Plug-ins are made for bussinees logics, like Update another record when the first one is created, make complex logic, etc...
What you need it is a javascript that executes on the OnLoad of the form and OnChange event in that OptionSet.
The lines you are looking for are:
function ShowField()
{
// The field is present on the form so we can access to its methods
var optionSet = Xrm.Page.getAttribute("custom_attribute");
if (optionSet == undefined)
{
return;
}
// The control is present on the form so we can access to its methods
var controlAddress = Xrm.Page.getControl("custom_address");
if (controlAddress == undefined)
{
return;
}
var valueOptionSet = optionSet.getValue(); // This is the value you set creating the OptionSet
switch (valueOptionSet)
{
case 0: // Your account value, show
controlAddress.setVisible(true);
case 1: // Your contact value, hide
controlAddress.setVisible(false);
default:
return;
}
}
You need to register a web resource and register the event, if you need more information about the code or why this stuff is here and why this not just tell me.

Docuemt postopen event not operating on profile document

I need to save serial number of the document in a profile document and here is a code of action Execute Script:
if (document1.isNewNote()){
var pdoc:NotesDocument=database.getProfileDocument("LastNumber","")
var lnm=pdoc.getItemValue("lastNumber")[0];
var inputText6:com.ibm.xsp.component.xp.XspInputText = getComponent("inputText6");
inputText6.setValue(lnm);
pdoc.replaceItemValue("lastNumber",lnm);
pdoc.save();
}
This code is not opening profile document at all. Any thing wrong in the code?
"LastNumber" is the name of the form used to create Profile Document ?
this profile document already exist ?
there are no reader fields in this profile document ?
you have an error on this line : var pdoc:NotesDocument=database.getProfileDocument("LastNumber","") ?
or you have debug it and see that pdoc is null ?
instead of pdoc.getItemValue("lastNumber")[0] you can use pdoc.getItemValueInteger("lastNumber") to get a typed result
I supposed that this field contains a number and you want to increment it
instead of using inputText field you can set value directly with document1.setValue("NumberField", lnm);
I second the caution Per is suggesting. Profile documents can be a beast. You should abstract access to the "next number" into a SSJS function call. Btw. in your code snippet you don't actually increment the last number. Also: if your input text control is bound, go after the data source, not the UI.
A crude way (I would use a managed application bean for better isolation) for a better function could be this:
if(document1.isNewNote() {
document1.setValue("DocumentNumber",applicationTools.getNextNumber());
}
Then in a SSJS library you would have:
var applicationTools = {
"getNextNumber" : function() {
synchronized(applicationScope){
var pdoc:NotesDocument=database.getProfileDocument("LastNumber","");
if (!applicationScope.lastNumber) {
applicationScope.lastNumber = pdoc.getItemValueInteger("lastNumber");
}
applicationScope.lastNumber++;
pdoc.replaceItemValue("lastNumber",applicationScope.lastNumber);
pdoc.save(); //Make sure pdoc is writeable by ALL!!!!
pdoc.recycle();
return applicationScope.lastNumber;
}
},
"someOtherUtility" : function(nameToLookup, departments) {
// more stuff here
}
}
Which, in some way has been asked before, but not for a profile field. Someone still could simply go after the applicationScope.lastNumber variable, which is one of the reasons why I rather use a bean. The other: you could do the saving asynchronously, so it would be faster.
Note: in any case the number generation only works when you have a non-replicating database. But abstracting the function opens the possibility to replace fetching the number from the profile with a call to a central number generator ... or any other mechanism ... without changing your form again.

Unboundid LDAP domain attributes

I need to evaluate an user's password expiration time against an Active Directory.
I'm using Android and Unboundid sdk. I can successfully connect to server using this code
final SocketFactory _socket_factory;
final SSLUtil _ssl_util = new SSLUtil(new TrustAllTrustManager());
try {
_socket_factory = _ssl_util.createSSLSocketFactory();
}
catch (Exception e) {
Log.e(LOG_TAG, "*** Unable to initialize ssl", e);
return null;
}
LDAPConnectionOptions _ldap_connection_options = new LDAPConnectionOptions();
_ldap_connection_options.setAutoReconnect(true);
_ldap_connection_options.setConnectTimeoutMillis(30000);
_ldap_connection_options.setFollowReferrals(false);
_ldap_connection_options.setMaxMessageSize(1024*1024);
LDAPConnection _ldap_connection = new LDAPConnection(_socket_factory, _ldap_connection_options, _host, _port);
BindRequest _bind_request = new SimpleBindRequest(_username, _password);
BindResult _bind_result = _ldap_connection.bind(_bind_request);
I retreive user attributes using a search
Filter _filter = Filter.create("(userPrincipalName=lorenzoff)");
SearchRequest _search_request = new SearchRequest(_server._base_dn, SearchScope.SUB, _filter);
But how can I read the domain's attribute 'maxPwdAge'? I can see it in among the domain attributes...
I need it to evaluate the remaining days until user's password expires.
I had the same issue and found a solution. the idea is simple you have to access the base DN and get that attribute:
SearchRequest _search_request = new SearchRequest(_server._base_dn,
SearchScope.BASE, "(objectClass=*)","maxPwdAge");
with this you should get the result with that attribute, if you get SearchRequest.ALL_USER_ATTRIBUTES you will have all the attributes shown on your screenshot.
That attribute is common for all users, the next thing you need to do is to search your specific user as you where doing before an get the attribute pwdLastSet, as you would expect it has the timestamp of the last time the user changed his password.
now is simple, you need to find the expiration date with the last time the user change it, and the password age
hope it helps
If maxPwdAge is an "operational" attribute, it must be explicitly requested as part of your search request. "User" attributes are returned (as permissions permit), but "operational" attributes must be explicitly requested. To request maxPwdAge create your request as follows:
SearchRequest _search_request = new SearchRequest(_server._base_dn,
SearchScope.SUB, _filter,"maxPwdAge");
The SeachRequest constructor actually accepts a variable length list of attribute types also:
SearchRequest _search_request = new SearchRequest(_server._base_dn,
SearchScope.SUB,_filter,"maxPwdAge","minPwdAge",
SearchRequest.ALL_USER_ATTRIBUTES);
requests maxPwdAge, minPwdAge, and all other user attributes. To request all operational attributes, use SearchRequest.ALL_OPERATIONAL_ATTRIBUTES.

Getting domain variables on layout

What is the best way to pass the model variables to layout in Grails? Specifically, I'm using Spring security plugin which has User class. I also have Contact class that looks like this:
class Contact {
String realname
String company
String mobile
String fix
String email
User user
...
What are the options for getting the currently logged in person's company in my layout (main.gsp)?
To add to the above answer, you could alternatively set a session variable for the user when you login in whatever controller method gets called.
You can also just set a session variable for the company in the controller method:
session.company = Contact.findByUser(session.user)?.company
or from the example above
session.company = Contact.findByUser(SecurityContextHolder.context.authentication?.principal)?.company
And in your main.gsp, something like:
<span id="companyName">${session.company}</span>
Do you mean that you need to pass this model for every page, automatically, instead of manual passing it at render at each of controllers? You can use filters there:
def filters = {
all(controller: '*', action: '*') {
before = {
request.setAttribute('loggedInPerson', SecurityContextHolder.context.authentication?.principal)
//Notice, that there is used original Authentication, from Spring Security
//If you need you can load your Contact object there, or something
}
after = {
}
afterView = {
}
}
}
and use loggedInPerson at your gsp:
Hello ${loggedInPerson.username}!
Btw, there is also Spring Security tags, that can help you without using your own filter, like:
Hello <sec:loggedInUserInfo field="username"/>!
If you want to add a certain object to the model, you can also use the "interceptors" provided by grails. To add a certain variable to a particular controller, you can use something like this.
def afterInterceptor = {model, modelAndView->
model.loggedInUser = getLoggedInUser() // retrieve your user details here
}
And you can retrieve loggedInUser in the main.gsp layout as ${loggedInUser}.
If you need to get these details in multiple controllers, you can create a BaseController and keep the afterInterceptor in this BaseController. All controllers which need the reference to the logged in user in their corresponding views should extend the BaseController.

Resources