Some PHP Session Security

When dealing with sessions, we have two types: Querystring and Cookie-based ones.

Cookie-based sessions are not visible for the user in the URL and are the safer ones, still
those cookies can actually get stolen or intercepted (e.g. some bad guy sniffing in the
open WLAN at your bar).

Querystring-based sessions are visible to you in the URL, the parameter name is
variable (it usually will contain the name session,sessid or sid for webmaster to
keep track) while the value is a unique identifier for your session (e.g. /index.php?sessid=1ad324afaw425fgtwe3r3).
Because they are visible, it may be even more easy to steal those,
because if you accidentally send the URL to somebody and not enough precautions are
taken, the person is suddenly logged in with your Account. Also, eavesdropping (the
friend standing behind you) or – as always – hacking / stealing can happen.

So here is the problem: If somebody gets the sessionid, he can access your account
without any login, and therefore do some nasty things.

How do we fix it?

Here’s a quick and dirty way:

session_start();
validateSession();

Shortly after creating the SESSION, you check for an existing IP in the Session, if none
is found we store the actual IP and a timestamp in the session. On each call we check IP
and timestamp, if the IP is the same, we do not do anything except update the timestamp
with the latest call. If the IPs are different, we look into our config (you will have
to create and include this ofc) if “time_exp_interval” is set. If so, we look up the time
interval that we allow (Note, that we check if the time between calls with different IPs is
SMALLER than the interval, not bigger. Why? If the user did not work for a few hours or 30
minutes, he maybe got assigned a different IP and we dont want to log him out. If the calls
with different IPs come within milliseconds then you can be sure there’s a second device involved)
and if the calculated time is smaller than the interval, we kill everything from the session we can.

function validateSession()
{
   if(!isset($_SESSION['ip']))
      $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
   else if($_SESSION['ip'] != $_SERVER['REMOTE_ADDR'])
   {
      //IP not matching, do we have some time expiration defined?//
      $diff = 0;
 
      //If time exp is set and a last action date, then check the whole thing//
      if($CONFIG['session']['time_exp_active'] && isset($_SESSION['laction']))
      {
         //Calc the difference//
         $diff = time() - $_SESSION['laction'];
 
         //Different IP within set interval, oh oh!//
         if($diff < $CONFIG['session']['time_exp_interval'])
         {
             //Kill everything we need and have//
             $_SESSION = array();
 
             //Delete any cookies if there are some//
             if (ini_get("session.use_cookies")) 
             {
                $params = session_get_cookie_params();
                setcookie(session_name(), '', time() - 42000,
                   $params["path"], $params["domain"],
                   $params["secure"], $params["httponly"]
                );
             }
 
             //And finally call session_destroy
             session_destroy();
 
             //Dont set lastlog//
             return;
         }
      }
   }
 
   //No different IP or time interval not met, update laction//
   $_SESSION['laction'] = time();
}

Note: You might want to make such a feature optional, as this will surely involve users
getting logged out more often than some would wish nowadays… sadly..

Dynamic JS / AJAX Polling

Hey folks,

Consider the following scenario: An application needs constant updates without page reloads and / or user-interaction (e.g. a presentation or a game or so). Ok, for small pages we just send an AJAX request every X seconds and check for updated content. This could become a problem though, if the amount of users increases drastically, (imagine some hundred users requesting status updates every 10 seconds, afaik Apache goes up to 400 max. requests at the same time (or per second, I don’t remember that) and goes loopy above these numbers, if not limited by config).

So what we are doing here: We will use some SQL capacity to handle your AJAX requests dynamically, in a more concrete way: Every (periodical) request to the AJAX update script (we assume it’s a PHP script echoing some JSON) will be logged with timestamp only.

We’ll then need to define somewhere (in a config, in the PHP file itself or in the DB) a max. amount of wanted connections per second, minute or whatever. The PHP script tests on every request (or by a separate periodical AJAX call, but be careful, this will maybe decrease SQL workload but generate additional requests) if the Connections / Time are above or below the specified limits.

If so, we will pass an additional JSON parameter, disable the JS function set by “setInterval()”, and re-set it with an increased or decreased time value. This whole script won’t do you any good for 1000 users coming in at the same time as the changes take some time to take effect, but it will provide a good and as fast as possible AJAX experience for a handful of users :)

So let’s get started, we’ll need four things:

-) A DB table with id and timestamp
-) The jQuery library up and running as I intend to use jQuery.get
-) The .php script which will serve your JSON data and the requests / time value.
-) A .js file (re-)binding and all the setInterval() functions

The table is pretty simple, we’ll just use a timestamp:

CREATE TABLE `connections` (
`time` TIMESTAMP NOT NULL
) ENGINE = MYISAM ;

I will not go into including jQuery and getting it to work, please get this info elsewhere if you’re not familiar with it.

For the PHP script, please note that I do have own functions for handling Database stuff, you’ll either want to do it the manual way using mysql_connect and so on, or you use your own lib:

<?php
   //Var MAXCONNECTIONS, this may come from a database, config, or from wherever//
   $MAXCONNECTIONS = 200;
 
   //Time interval in seconds, for CONNECTIONS / INTERVAL,  I'll take 200 connections every 5 secs for now//
   $INTERVAL = 5;
 
   //On every call of the page, log an entry//
   database::ExecutePrepared("INSERT INTO connections(time) VALUEs(?)", time());
 
   //Get whatever stuff your application needs to get//
   $result = database::ExecutePrepared("SELECT * FROM whatever");
 
   //Get the connections per second, the parameter passed will set if you have connections per second, per minute, or whatever.. just detract the wanted value from actual timestamp//
   //I'll take 200 connections per 5 seconds for now//
   $connections = database::ExecutePrepared("SELECT COUNT(*) AS cs FROM connections WHERE time > ?", (time() - $INTERVAL));
 
   //I'll extract the value without foreach loop//
   $connections = $connections[0]['cs'];
 
   //Some math, we divide MAXCONNECTIONS by actual connections//
   $factor = $MAXCONNECTIONS / $connections;
   //This will give us a factor, that we can divide through our JS timeout value (NOT MULTIPLY), may not be 100% exact all the time, but pretty good//
 
   //And echo GOOD VALID JSON (!) Your JS callback function will NOT be called if using the "json" parameter and recieving bad json,
   //this will make debugging hard as hell You can test your JSON here: http://jsonlint.com/
   $txt = "{\"connections\":\"".$factor."\",\"mydata\":{";
 
   //Just a little param, I like building strings that way//
   $first = true;
 
   //Loop through results and include mydata, the Database values you include can be whatever data you wish//
   foreach($result as $item)
   {
      if($first)
         $txt .=  "\"".$item['id']."\":\"".$item['value']."\"";
      else //Basically the same, but with leading comma
         $txt .=  ",\"".$item['id']."\":\"".$item['value']."\"";
   }
 
   //Close the beginning and mydata JSON bracket//
   $txt .= "}}";
 
   //And echo our good stuff
   echo $txt;
?>

Don’t forget to have a cronjob running to clean up the connections table, or kill everything older than your time defined in the php script itself.

So much for the PHP part, this is highly customizable, we’re only interested in the “connections” parameter. If you do not wish to return the value
with every data request to the page, you can set another intervalFunction that ONLY checks the connections / second, but depending on your timeout
value you’ll generate more connections.

Now to the JS part, shouldn’t be too difficult:

The page only needs to contain this (apart from inclusion of our .js file ofc):

$(document).ready(function() { setupFunc(); });

This may be familiar to you, it will ensure no JS is executed before the page has loaded (Hard to change any code that is not there yet :) .

And our JS file finally will contain:

//Set this global, we will need it//
var intervalhandle;
 
//Updateinterval
var updateinterval = 5000;
 
//This will call the checkForUpdates() function every 5 seconds or 5000 milliseconds//
function setupFunc()
{
   intervalhandle = window.setInterval(function(){
      checkForUpdates();
   }, updateinterval;
}
 
//Call the page with no GET data, use jQuery.post if you want to include data in the request as well, set doUpdates as callback function and output format JSON//
function checkForUpdates()
{
   jQuery.get("./myurl.php", null, doUpdates, "json");
}
 
//Does the updates with your data, and updates the checkForUpdates() interval accordingly//
//If the func is not called (test with console.log or so) you probably have bad JSON passed as data//
function doUpdates(data)
{
   //YOu can process data BEFORE updating the interval, or after, you need to choose that depending on the update workload and your needs//
   if(data['mydata'] != undefined)
   {
      mydata = data['mydata'];   
 
      //DO WHATEVER YOU WISH WITH MYDATA//
   }
 
   //AND FINALLY SET THE NEW INTERVAL
   if(data['connections'] != undefined)
   {
      //calc the new interval//
      updateinterval = updateinterval / data['connections'];
 
      //This is what we need the handle for, clear the intervalfunction//
      window.clearInterval(intervalhandle);
 
      //And reset it with new value, just call the setupFunc() again//
      setupFunc();
   }
}

That’s it, as long as you have a stable amount of users on your dynamic updated page, this will ensure that you’ll always stay on your wanted amount of connections/time.
If new users join, it will ofc take a while depending on current update interval for changes to take effect.
Do not set the interval in the .js file too low, saying “well it will be adapted anyway”, that could give you problems if a lot of users join at the same time.

That’s it, hope it helps you out, of course it wont solve every scenario but can be good for a lot of them :)
One thing you could include, but I didn’t: The initial update Interval used by JS is echoed by a PHP script (somewhere hidden in the source code), and you have PHP
taking account of that in advance, even before the requests start to come in, if you choose a wider update interval for new users, other clients will have time to adapt!

If you find any errors feel free to message me, as I wrote the code above in the wordpress editor without testing, but it should be fine :)

jQuery tablesorter quickie

Hey folks,

This is a really short notice, as most info is available on the web anyway:

I recently learned about a jQuery plugin that’s reeeeally easy to use, and it allows you to sort any column of one or more tables with just one click.

Here’s what you need:

The tablesorter: http://tablesorter.com/__jquery.tablesorter.zip (upload it to a location which is accessible from the web)

jQuery (https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js), by the time you read this there may be a later version available, just check google code.

And this is how you do it:

Include jQuery and your tablesorter

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://path.to.tablesorter.js"></script>

And initialize the tablesorter:

<script type="text/javascript" language="javascript">// <![CDATA[
  $(document).ready(function()      {          $("#content-table").tablesorter();      }  );
// ]]></script>

The jQuery selector used must identify the table (in my case an id of “content-table”).

You’ll of course need a table, with “thead” and “tbody” sections.
Table headers in the thead section will trigger the sorting, tbody contains data to get sorted.

In case you’ll have like HTML tags and complex stuff within your table, you’ll need to add a textExtraction property to your tablesorter init:

<script type="text/javascript" language="javascript">// <![CDATA[
  $(document).ready(function()      {          $("#content-table").tablesorter( { textExtraction:"complex"} );      }  );
// ]]></script>

The value “complex” can be replaced by a function of yours, which has to return the plain text to be sorted without any tags and so on.

Ok, since this was supposed to be a quickie, we’re done, check the official page for further info: http://tablesorter.com/docs/

Cya

IBM BigInsights – What I’ve learned

Hey,

I just felt like I’d need to share what I learned about installing IBM BigInsights (Enterprise 1.3.0.0 on a RHEL 6) with you. It’s not that much, but hopefully helpful and I might add more stuff, I didn’t get everything to work yet :)

1.) Do a single-node installation and add more nodes later through the console, that will save you checking long install logs, uninstalling and reinstalling if something goes wrong.

2.) IF the installation fails or goes wrong for some reason, don’t do a reinstall, uninstall completely.

Unfortunately the uninstall.sh will not do this properly and leftover stuff may corrupt future installations.

See this post on how to do it properly: http://www-304.ibm.com/support/docview.wss?uid=swg21593340

3.) As the installer states, check the installation logs if something goes wrong (simple-fullinstall.xml and a install_date_time.log), both files are found in
your extracted tarball.

4.) A nasty bug, if your installer gets stuck while installing sheets at 94%, try this workaround (should be fixed in 1.4.0.0):

Locate this file:/installer/hdm/components/console/binary/overlay/bin/stop-console.sh/stop-console.sh

Locate the following code-part and replace the commented line with the new one (see code comments):

if kill -0 `cat $GERONIMO_PID` &>/dev/null; then
echo Stopping $server_name...
#comment out the following line
#$wasce_home/bin/shutdown.sh --user $wasce_user --password $wasce_pwd --port $ctrlport
#add the following command instead
kill -9 `cat $GERONIMO_PID` &>/dev/null
exit $?

That’s it for now, I’ll surely find more ;)

PHP Tokenizer

Hey there :)

I finally found some time to write something new, I think this is gonna be quite useful:

What we’re writing, is a tokenizer for strings, better said for search strings like the ones used e.g. in google, but a bit more simplified.

Here is an example for a string passed to this function:

author:vinci -free content:/tokenizer/ -”not this string”

The output generated by our code would look like this:

array(array(“type” => “string”, “target” => “author”, “not” => false, “value” => “vinci”), array(“type” => “string”, “target” => “none”, “not” => true, “value” => “free”), array(“type” => “regex”, “target” => “content”, “not” => false, “value” => “tokenizer”), array(“type” => “string”, “target” => “none”, “not” => true, “value” => “not this string”))

The output can be easily used in a foreach loop for easy filtering from a SQL database or PHP array containing the data.

Of course the possible combinations can be adapted by yourself, this special case I’m writing here is used for filtering RSS feeds (author, content, title, feed-url).

Ok lets start this:

public function tokenize($filter)
{
        //Main output array//
    	$output = array();
 
    	//Incomplete flags//
    	$incompleteregex = false;
    	$incompletestring = false;
 
    	//Output array item as described in func description//
    	$tempitem = array();
}

These are only inits, the main output array containing all arrays with our single filter items, flags if we have a regex or string started that we have to complete, and our single array items, which are an array by themselves.

(Note: Code from now on is added on the bottom of our function, but still inside it).

We need a Loop to iterate through all our chars:

//Main loop//
    	for($i = 0; $i < strlen($filter); $i++)
    	{

and we want to know the actual char we’re processing:

    		//Get the actual char//
    		$actualchar = substr($filter, $i, 1);

Ok, now the first thing we want to do, is check if we have a minus sign “-”, but ONLY if our array is still empty. If our array contains any value already, it means that a minus sign may not occur, or if it does it’s part of our regex or string:

//Check for minus only if $tempitem still empty//
    		if(empty($tempitem))
    		{
    			//Set target to content by default//
    			$tempitem['target'] = "content";
    			$tempitem['type'] = "string";
 
    			//Initialize value//
    			$tempitem['value'] = "";
 
    			//If empty $tempitem and whitespace => ignore//
    			if(preg_match('/\s/',$actualchar))
    				continue;
 
    			if(strcmp($actualchar, '-') === 0)
    			{
    				$tempitem['not'] = true;
    				continue;
    			}
    			else
    				$tempitem['not'] = false;
    		}

So what we are doing here, is:
- If our array is empty, we initialize it with some default values, so this code will not be executed anymore for the actual array.

- If the char is a whitespace we’re ignoring it (We could also use trim onto our passed value, but that would work only for start and end, not for the values in between (those are also separated by whitespaces, and we want to ignore multiple ones).

- finally we compare the actual char to “-”, if it is, we set our “not” value to true and continue on to the next char, else we set “not” to false and don’t continue, but finish the loop to see how we need to process the char.

Ok, so at this point we’ve processed all not-needed whitespaces and the minus sign. The next thing that may occur is a scope for the filter, say “author” or “title”. The characteristic of these values is, that they are terminated by a “:”, therefore we can check on the “:” sign and compare what we’ve stored as string so far:

//Check for : //
    		if(strcmp($actualchar, ':') === 0)
    		{
    			//Now see if we have a valid value stored in value//
    			if(strcmp($tempitem['value'], "author") === 0)
    			{
    				$tempitem['target'] = "author";
    				$tempitem['value'] = "";
    				continue;
    			}
    			else if(strcmp($tempitem['value'], "url") === 0)
    			{
    				$tempitem['target'] = "url";
    				$tempitem['value'] = "";
    				continue;
    			}
    			else if(strcmp($tempitem['value'], "title") === 0)
    			{
    				$tempitem['target'] = "title";
    				$tempitem['value'] = "";
    				continue;
    			}
                 }

What we did, is: If we read a “:” char, we compare all our chars stored into $tempitem['value'] (the storing is done at the end of the function, we’ll come to this later), or rather we compare the string we’ve stored, with one of the scopes given above (title, url, author). If we do have a exact match, we can set our target to the according value and clear our value we had up to now, because the scope is stored in “target” and we want keywords in “value” only.

The next step is – if our value is empty – to check the actual char for the start sign of a string or a regex:

//If empty, check for start of string or regex//
    		if(empty($tempitem['value']) !$incompletestring && !$incompleteregex)
    		{
    			if(strcmp($actualchar, "/") === 0)
    			{
    				$tempitem['type'] = "regex";
    				$incompleteregex = true;
    				continue;
    			}
    			else if(strcmp($actualchar, '"') === 0)
    			{
    				$tempitem['type'] = "string";
    				$incompletestring = true;
    				continue;
    			}
    		}

We set the according flags, that tells us that all subsequent chars are to be interpreted as part of a string or regex and therefore whitespaces do not trigger a new array item. We do not jump into this code, if our value is still empty but one of our incomplete flags is set, because that would mess up everything (our flags would still be set).

The next part of code is run if we have a incomplete flag set, the actual char is the according ending char for the regex or string (depending on our flag), and our value is not empty. If we have a regex, we test for a valid regex, else we throw an exception. Finally we need to check, if we have processed the last char of the string, because in this case we need to push the last item onto the output array now already:

//regex or string to finish?//
    		if(!empty($tempitem['value']) && $incompleteregex && strcmp($actualchar, "/") === 0)
    		{
    			$incompleteregex = false;
 
    			//Check for good regex//
    			if(preg_match("§".$tempitem['value']."§", "http://w3.ibm.com") === false)
    				throw new InvalidArgumentException("The regex ".$tempitem['value']." is not a valid regex!");
 
    			//Last char?//
    			if($i == (strlen($filter) -1))
    			{
	    			//remove whitespaced//
	    			$tempitem['value'] = trim($tempitem['value']);
	    			//Push output//
	    			array_push($output,$tempitem);
    			}
 
    			continue;
    		}
    		else if(!empty($tempitem['value']) && $incompletestring && strcmp($actualchar, '"') === 0)
    		{
    			$incompletestring = false;
 
    			//Last char?//
    		   	if($i == (strlen($filter) -1))
    			{
	    			//remove whitespaced//
	    			$tempitem['value'] = trim($tempitem['value']);
	    			//Push output//
	    			array_push($output,$tempitem);
    			}
    			continue;
    		}

And finally, this takes us to the part, were – if no special case happend until now – we add our char to the “value”:

    		//If no check applied, add our char//
    		$tempitem['value'] .= $actualchar;
</php>
 
And the last part: If we have no incomplete flag set and read a whitespace, we push the actual temp-array into our output arraay and reset the temp-array:
 
<pre lang="php">
//No regex & string to finish and whitespace//
    		if(!$incompleteregex && !$incompletestring && (preg_match('/\s/',$actualchar) || ($i == (strlen($filter) -1))))
    		{
    			//remove whitespaced//
    			$tempitem['value'] = trim($tempitem['value']);
    			//Push output//
    			array_push($output,$tempitem);
    			//Reset values//
    			$tempitem = array();
    			$incompleteregex = false;
    			$incompletestring = false;
    		}
    	}
 
    	return $output;
    }

Don’t forget to reset the flags and return the output array :)

That’s it, hope it helped.. the complete code will be uploaded in the next days in the codeland lib, in the “utilityfunctions.php”.

Have a nice day.

I’m feeling lucky

Hi,

Sorry for the delay since the last post. I have been working on a tutorial for writing a
tokenizer in PHP, but it’s not at a point to be published yet. I have been busy with other
stuff, mainly reading a whole lot of books and getting into making music (I play all kind
of guitars and recently bought a MIDI-Keyboard, and now I’m trying to get Ableton, Cubase
and Fruity Loops figured out :)

Today I wanted to share one of the books I’m reading with you that a friend of mine working
in the UK atm mentioned: “I’m feeling lucky” by Douglas Edwards.

http://www.amazon.co.uk/Im-Feeling-Lucky-Confessions-Employee/dp/1846145120/ref=sr_1_1?ie=UTF8&qid=1329925036&sr=8-1

Basically it’s an autobiography of one of the first non-engineers that signed with google and it’s a great view on to how a small company noone cares about gets huge in a small amount of time. You’ll be amazed by Google’s (and thus Larry Page’s and Sergey Brin’s) points of views and personalities.

Anyway, the book is full of humor, interesting stories and more importantly, if you see Google’s spur and are almost able to feel it, maybe you can make part of it your own, and use it to get to things more dynamically and enthusiastic.

Have fun :)

Modifying the twenty-eleven theme

Hey there,

This will cover how to modify the twenty-eleven theme slightly, or better said, the categories sections:

As I’ve noticed, the theme is better than the old twenty-ten one, but it has one huge disadvantage (in my opinion, maybe some people just want that):

When browsing by category, the posts are all full length, which makes browsing through categories somewhat hard, ’cause you have to scroll a lot.. But this was different in twenty-ten, where the posts were displayed as excerpt with a “Read more” link, so I wanted to adapt twenty-eleven to behave as twenty-ten when browsing categories.

The thing we are looking for is the /wp-content/themes/twentyeleven/content.php file. It is basically a rendering file for all template content.

After reading a bit through it you will find these parts:

<?php if ( is_search() ) : // Only display Excerpts for Search ?>
<div class="entry-summary">
	<?php the_excerpt(); ?>
</div><!-- .entry-summary -->
<?php else : ?>
<div class="entry-content">
	<?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?>
	<?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
</div><!-- .entry-content -->
<?php endif; ?>

So if you use the search function, you will see the template does exactly the same thing we want it to do with categories as well, which would be display the thing only as excerpt. So we only have to add a “|| is_category()” to the If-Clause checking whether the whole thing is a search:

<?php if ( is_search() || is_category() ) : // Only display Excerpts for Search and categories?>
<div class="entry-summary">
	<?php the_excerpt(); ?>
</div><!-- .entry-summary -->
<?php else : ?>
<div class="entry-content">
	<?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?>
	<?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
</div><!-- .entry-content -->
<?php endif; ?>

That’s it, nothing more needed.. WordPress is pretty cool, huh? :)

How to work with DomainService Class

Hello folks,

today i want to show you some tipps which you can need when you first work with the DomainService Class.

Tip 1:
Problem: My Entities/Tables are not shown at the creation Context

Solution: You have to Create your Web Project first. After that you should see all your Entities/Tables of your Database in the context.

Tip 2:
Problem: When you create a new DomainService two files were created. *.cs and a *.metadata.cs file.
If you have selected several tables, the complete code will saved in one file. This can be very confusing.
I love it to have all structured and clear. So i create for each Entitie a new File.

Solution:
For example you create a DomainService with the name “DomainService” which contain two Entities “ExampleTable” and “AnotherTable”.
Now open the DomainService.cs file. In this file you see something like this(shorten Version):

DomainService.cs

namespace TestProject.Web.Services
{
    using System;
    [...] // Some other usings
 
    [EnableClientAccess()]
    public class DomainService : LinqToEntitiesDomainService<TestEntities>
    {
	// Methods of ExampleTable
	public IQueryable<ExampleTable> GetExampleTable(){[...]}
 
        public void InsertExampleTable(ExampleTable ExampleTable) {[...]}
 
        public void UpdateExampleTable(ExampleTable currentExampleTable){[...]}
 
        public void DeleteExampleTable(ExampleTable ExampleTable) {[...]}
 
	// Methods of AnotherTable
	public IQueryable<AnotherTable> GetAnotherTable(){[...] }
 
        public void InsertAnotherTable(AnotherTable AnotherTable) {[...] }
 
        public void UpdateAnotherTable(AnotherTable currentAnotherTable){[...]}
 
        public void DeleteAnotherTable(AnotherTable AnotherTable){[...] }
    }
}

What you now have to do is to create two new cs files. The names should be like this:

DomainService.ExampleTable.cs
DomainService.AnotherTable.cs

Now Copy the complete DomainService.cs file in it and delete

[EnableClientAccess()] in each file

After that you have to make the class to a partial class, so you have to change it like this:

public partial class DomainService : LinqToEntitiesDomainService

Now delete in each file the other Entities Methods.

The two files should look like this:

DomainService.ExampleTable.cs

 
namespace TestProject.Web.Services
{
    using System;
    [...]
 
    public partial class DomainService : LinqToEntitiesDomainService<TestEntities>
    {
	// Methods of ExampleTable
	public IQueryable<ExampleTable> GetExampleTable(){[...]}
 
        public void InsertExampleTable(ExampleTable ExampleTable) {[...]}
 
        public void UpdateExampleTable(ExampleTable currentExampleTable){[...]}
 
        public void DeleteExampleTable(ExampleTable ExampleTable) {[...]}
	}
}

DomainService.AnotherTable.cs

 
namespace TestProject.Web.Services
{
    using System;
    [...]
 
    public partial class DomainService : LinqToEntitiesDomainService<TestEntities>
    {
	// Methods of AnotherTable
	public IQueryable<AnotherTable> GetAnotherTable(){[...] }
 
        public void InsertAnotherTable(AnotherTable AnotherTable) {[...] }
 
        public void UpdateAnotherTable(AnotherTable currentAnotherTable){[...]}
 
        public void DeleteAnotherTable(AnotherTable AnotherTable){[...] }
	}
}

If you have done it in both files you now need to edit the DomainClass.cs file.

Make it even to partial and delete the Methods in the class so it lookes like this:

DomainService.cs

namespace TestProject.Web.Services.DomainService
{
    using System;
    [...]
 
    [EnableClientAccess()]
    public partial class DomainService : LinqToEntitiesDomainService<TestEntities>
    {
    }
}

Now you are finished. This is a lot clearer for you now. The Compiler still see this as one file.
If you want to append your Service with a new IQueryable Method you dont have to search through the complete file.

Additional you can create a seperate folder for each DomainService.

Tip 3:

Problem: How to make Query over many Tables?

Solution:
The magic word is “Include”.
First you have to add the [Include] attribute in the metadata class to a EntityCollection of your Table you want to access.

Now you have to have to include the Table in the Query.

public IQueryable<ExampleTable> GetExampleTable()
{
	return this.ObjectContext.ExampleTable.Include("AnotherTable").Inlcude("AnotherTable.TableStatus").OrderBy(t => t.Table.TableID);
}

Now all Data of “AnotherTable” and “AnotherTable.TableStatus” were included and you can access them.

Tip 4:

Problem: How can i check what my DomainService returns and debug it?

Solution:
This is very simple, but a good trick.

public IQueryable<ExampleTable> GetExampleTable()
{
	var query = this.ObjectContext.ExampleTable.Include("AnotherTable").Inlcude("AnotherTable.TableStatus").OrderBy(t => t.Table.TableID);
	return query;
}

If you now add a breakpoint at “return query;” you can see the result of the query and which data were given back.

Check your logs and refrain from using standard users!

Hi there, this little story just happened today and I spent a few hours dealing with it, so here’s some advice for you:

1.) What happened?

3 days ago, I got an e-mail by my server provider, notifying me of the fact, that an attack was started from my server:

Abuse-Message [AbuseID:050F17:13]: AttackOutLevel: OUT Attack notification for IP 78.47.151.213 (Router: juniper1.ffm.hetzner.de) [Network-Normal]‏

The next thing I did, was check my “ufw” rules, allowing only SSH, 8080, 80 (for HTTP), FTP and my Teamspeak3 Ports and denying everything else. I guessed that would work! But no, 3 days later (today) again:

Abuse-Message [AbuseID:051597:12]: AbuseNormal: 78.47.151.213 from your network is sending flood traffic at high pps rate – Please notify customer!‏

2.) What I did?

Ok, so I slowly was getting angry, why the heck won’t these idiots just let me run my poor little server in peace? Good, now the real checking of the issue began:

root@Ubuntu-1010-maverick-32-minimal:~# lastlog

The lastlog command prints a list of all users on the system, including last login date and from where the login took place… here are the first few lines of my system.
Username         Port     From             Latest
root             pts/7    chello0801080261 Fri Sep 23 16:56:35 +0200 2011
daemon                                     **Never logged in**
bin                                        **Never logged in**
sys                                        **Never logged in**

There were only 3 users that had a last-login, so the checking wasn’t too much work: I immediately noted, that my user “teamspeak” had a last login of 3 days ago.. but the last and only time I used that one, was when I set up my teamspeak server some months ago. The “From” value, showed up a german domain. Don’t wanting any further problems, the next thing I ran was a

ps -u teamspeak

command, which would show all active processes by the user and oh look, he had a “httpd” started.. I sadly don’t remember what the other process was, but I killed them both anyway. The next step was to delete the user. The command

userdel teamspeak

did the trick actually, but don’t forget to delete the users “/home/” directory (in my case “/home/teamspeak”).

Now I moved on to check the authentication logs, which can be found at
/var/log/auth.log
Since the logs showed a lot of entries, I preferred downloading them with WinSCP and had a look at it using Notepad++! The result looked pretty disconcerning. A lot of entries were like this:
Sep 18 12:07:37 Ubuntu-1010-maverick-32-minimal sshd[20187]: Invalid user muie from 85.25.191.144
Sep 18 12:07:37 Ubuntu-1010-maverick-32-minimal sshd[20187]: pam_unix(sshd:auth): check pass; user unknown
Sep 18 12:07:37 Ubuntu-1010-maverick-32-minimal sshd[20187]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=static-ip-85-25-191-144.inaddr.ip-pool.com
Sep 18 12:07:39 Ubuntu-1010-maverick-32-minimal sshd[20187]: Failed password for invalid user muie from 85.25.191.144 port 44321 ssh2
Sep 18 12:07:39 Ubuntu-1010-maverick-32-minimal sshd[20190]: Invalid user minecraft from 85.25.191.144
Sep 18 12:07:42 Ubuntu-1010-maverick-32-minimal sshd[20190]: Failed password for invalid user minecraft from 85.25.191.144 port 44598 ssh2
Sep 18 14:26:40 Ubuntu-1010-maverick-32-minimal sshd[20338]: Failed password for invalid user t1na from 174.132.219.26 port 36168 ssh2

The logfile actually has 9000 entries for the last 6 days, with only a few being my login as root. Ok, I suppose such logs are quite normal for something connected to the internet, but anyway  I added the most used IP addresses to my ufw blocklist using

ufw deny from 66.66.66.66

where 66.66.66.66 is the IP-Adress you want to block. But I still wanted to know what happened to my “teamspeak” user and voila:
Sep 18 12:14:04 Ubuntu-1010-maverick-32-minimal sshd[20229]: Accepted password for teamspeak from ******** port 40760 ssh2
Sep 18 12:14:04 Ubuntu-1010-maverick-32-minimal sshd[20229]: pam_unix(sshd:session): session opened for user teamspeak by (uid=0)
Sep 18 12:15:16 Ubuntu-1010-maverick-32-minimal passwd[20267]: pam_unix(passwd:chauthtok): password changed for teamspeak
Sep 18 12:15:21 Ubuntu-1010-maverick-32-minimal sshd[20243]: Received disconnect from  ********: disconnected by user
Sep 18 12:15:21 Ubuntu-1010-maverick-32-minimal sshd[20229]: pam_unix(sshd:session): session closed for user teamspeak

So my guess was correct, the “teamspeak” user has indeed been hacked. Since the IP address that changed my user’s password had a page associated with it (and a contact given there), I mailed them to stop doing this or I would take legal actions, and here is what I got as reply some minutes afterwards:

Dear Mr Sessa,

thanks for informing us about a possible security leak on our server. We checked this thoroughly and detected a hacked password of a widely limited shell user; from this time on, SSH connections have been made to other servers, including yours. We removed this user and additionally disabled other unneeded users.

Sorry for any inconveniences.

Regards

Well, I guess I’ll just believe what they say.. the bad guys can’t be traced that easily I suppose :)

Conclusion

I really don’t know how they managed to find out the password of the TS user (I can’t remember which one I set, but usually my passwords are crack-safe). My best suggestion would be, that the server had a security hole in it (for it was a Release Candidate version). I set up a new server (final version, not RC) with a new user (this time not “teamspeak”) and a even harder password, and hope this won’t happen again.

What I’ve also learned is, that I’ll never use the standard usernames again (the failed login attempts include usernames like “mysql”, “minecraft”, “teamspeak”, “root”).

For my part, I hope that this whole s…ituation is over ;)