Jason Simmons, Freelance it consultant

How to connect Symfony2 with IPBrick LDAP using KnpUGuard

Posted on August 28, 2015
Filed Under IT Solutions | Leave a Comment

After posting on Twitter my frustrations on trying  to connect Symfony2 to a LDAP server, I got a tweet back from Ryan Weaver pointing me at https://knpuniversity.com/screencast/guard. After a few hours of tinkering i had managed to achieve integration with a LDAP server based on a IPBrick communications server. IPBrick has a extremely easy interface to manage a ton of LDAP users and  groups. No importing of LDIF files and weird queries etc.

I can now actually get the LDAP server to do its job and authenticate people.

Until  KnpuGuard, symfony was actually getting in the way  (Yes I know it is a perceived complexity, it is actually very simple ??) insisting that it authenticate users directly , even if i could figure out how to get it to pull the users out of the LDAP server.

I’m going to show you how *I* did it.

Please note:
I’m not a developer by trade, I’m a Infrastructure/Entrepreneur/Hacker type guy. Don’t start fitting with rage if I don’t use the correct Dependency Injections methods, and Symfony services and factories, classfull form objects and nonce’s and blah blah and other associated computer science “best practices” which don’t actually help you make any money.

All this “blah” is one of the key reasons why LDAP integration in symfony2 is so hard. KnpuGuard makes it a lot easier. I don’t need any local entities in symfony2, all the adds moves and changes will be performed by the IPBrick server LDAP GUI.

This just shows you how to get over this first hurdle. The rest is up to you.

I created a bundle called Enginebundle and created a Security directory and put the following files in it. These I got from the instructions on the KnpuGuard documentation. This is a very high level overview. But I’m sure it will give you enough clues to help you do the same.

The real power is used in the LdapUserprovider.php. This tries to login to the LDAP server using the credentials supplied by the user. If the details are correct, it pulls roles (AKA Groups), email address, SIP address and even photograph from LDAP server and populates the User class.

I now can successfully integrate LDAP by focusing on 4 key files.

  1. The form Authentication class
  2. The User class to hold user details taken from LDAP
  3. A LDAP Class that has all the methods to do LDAP stuff
  4. The User provider which use’s my LDAP class to popular the actual symfony class

The rest of the application development is business as usual for symfony2

User Login Form against LDAP

User Login Form against LDAP

 

Successful Login, Photo and other details pulled from LDAP

Successful Login, Photo and other details pulled from LDAP

LdapUser.php the new User class to be used by Symfony2

// LdapUser.php, to hold the user details and filled by LDAP
namespace Trensys\EngineBundle\Security;

use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;

class LdapUser implements UserInterface, EquatableInterface {

    private $username;
    private $email;
    private $photo;
    private $sipaccount;
    private $uid;
    private $password;
    private $salt; // Not really used by LDAP, would be nice !
    private $roles;
    private $displayname;
    private $description;
    private $status;
    private $mailhost;

    public function __construct($username, $password, $salt, array $roles) {
        $this->username = $username;
        $this->password = $password;
        $this->salt = $salt;
        $this->roles = $roles;
    }

    public function setMailhost($mailhost){
        $this->mailhost = $mailhost;
    }
    
    public function getMailhost(){
        return $this->mailhost;
    }
    
    public function setStatus($status) {
        $this->status = $status;
    }

    public function getStatus() {
        return $this->status;
    }

    public function setUid($uid) {
        $this->uid = $uid;
    }

    public function getUid() {
        return $this->uid;
    }

    public function setSipaccount($sipaccount) {
        $this->sipaccount = $sipaccount;
    }

    public function getSipaccount() {

        return $this->sipaccount;
    }

    public function setPassword() {
   // Hack to remove LDAP password once user has been found.
   // is also used to find the user and attempt Login
    }

    public function setUsername($username) {
        $this->username = $username;
    }

    function setDisplayname($displayname) {
        $this->displayname = $displayname;
    }

    function getDisplayname() {
        return $this->displayname;
    }

    function setDescription($description) {
        $this->description = $description;
    }

    function getDescription() {
        return $this->description;
    }

    function setPhoto($photo) {
        $this->photo = $photo;
    }

    function getPhoto() {
        return $this->photo;
    }

    public function setEmail($email) {
        $this->email = $email;
    }

    function getEmail() {
        return $this->email;
    }

    public function getRoles() {
        return $this->roles;
    }

    public function getPassword() {
        return $this->password;
    }

    public function getSalt() {
        return $this->salt;
    }

    public function getUsername() {
        return $this->username;
    }

    public function eraseCredentials() {
        
    }

    public function isEqualTo(UserInterface $user) {
        if (!$user instanceof WebserviceUser) {
            return false;
        }

        if ($this->password !== $user->getPassword()) {
            return false;
        }

        if ($this->salt !== $user->getSalt()) {
            return false;
        }

        if ($this->username !== $user->getUsername()) {
            return false;
        }

        return true;
    }

}

Now we have the user we need to create the LdapUserProvider.php which is called by Guard, and we also need to create class (ipbrickLDAP.php) that the provider can use to do all the LDAP query stuff, all in one place.

LdapUserprovider.php, which is a service, and referenced in security.yml as a provider

namespace Trensys\EngineBundle\Security;

use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;

class LdapUserProvider implements UserProviderInterface 
{ 
    private $user_ldap_password;
    private $ipbrickLdap;
    
    public function setLdapPassword($password){
        $this->user_ldap_password = $password;
    }
    
    public function loadUserByUsername($username)
    {
        // Will import this into parameters.yml at one stage
        
        $password = $this->user_ldap_password;
        $ldaphost = "ipbrick.ftw.co.uk";
        $ldapport = 389;
        $basedsn = "dc=ftw,dc=co,dc=uk"; 
        $this->ipbrickLdap = new ipbrickLdap($ldaphost, $ldapport, $basedsn);
        $ldapsearch = $this->ipbrickLdap->Login($username, $password);
  
$defaultPhoto="paste base64 encode of default jpeg here";
        if ($ldapsearch) {
            
            $user = new LdapUser($username, $password, "notused", $ldapsearch['roles']);
            // Map the fields from the LDAP use to the symfony user

            $user->setPassword($password); // Dont forget to hash this somehow
            $user->setEmail($ldapsearch['email']);
            $user->setUsername($username);
            $user->setDisplayname($ldapsearch['displayname']);
            if( isset($ldapsearch['otherdata'][0]['jpegphoto'][0])){
                $user->setPhoto($ldapsearch['otherdata'][0]['jpegphoto'][0]);
            }else{
                $user->setPhoto($defaultPhoto);
            }
             if( isset($ldapsearch['otherdata'][0]['description'][0]) ){
                $user->setDescription($ldapsearch['otherdata'][0]['description'][0]);
            }else{
                $user->setDescription("You have a number not a name: ".$ldapsearch['otherdata'][0]['uidnumber'][0]);
            }
            
            $user->setStatus($ldapsearch['otherdata'][0]['accountstatus'][0]);
            $user->setUid($ldapsearch['otherdata'][0]['uidnumber'][0]);
            $user->setSipaccount($ldapsearch['otherdata'][0]['mail'][0]);
            $user->setMailhost($ldapsearch['otherdata'][0]['mailhost'][0]);

            return $user;
        }
        // Throw an Exception, Either the user can not be found in the LDAP OR
        // The user could not login, SO lets just say that the user can not be 
        // found until he supplies the right username and password :-)
        throw new UsernameNotFoundException(
            sprintf('Sorry these details are not correct.', $username)
        );
    }

    public function refreshUser(UserInterface $user)
    {
        if (!$user instanceof LdapUser) {
            throw new UnsupportedUserException(
                sprintf('Instances of "%s" are not supported.', get_class($user))
            );
        }
       // return $this->loadUserByUsername($user->getUsername());
        return $user;
    }

    public function supportsClass($class)
    {
        return $class === 'Trensys\EngineBundle\Security\LdapUser';
    }
}

ipbrickLDAP.php Does all the LDAP Stuff, used by the provider

namespace Trensys\EngineBundle\Security;

class ipbrickLdap {

    var $ldaphost;
    var $ldapport;
    var $ldapconn;
    var $basedn;
    var $domain;
    var $errormessage;
    var $username;

    public function __construct( $ldaphost,$ldapport, $basedsn) {
     

        $this->ldaphost = $ldaphost;
        $this->ldapport = $ldapport;
        $this->basedn   = $basedsn;
    }

    /*****************************************************************
     * FetchAllUsers()
     *****************************************************************/

    function FetchAllUsers() {
        $this->errormessage = null;
        $this->ldapconn = ldap_connect($this->ldaphost, $this->ldapport);

        if (!$this->ldapconn) {
            $this->errormessage = "Error: FetchAllUsers() could not get a connection to the LDAP Server";
            return FALSE;
        }
        
        $usersBase = "ou=Users,".$this->basedsn;
        $result = ldap_search($this->ldapconn, $usersBase, "(objectClass=*)");
        $userdata = ldap_get_entries($this->ldapconn, $result);

        ldap_close($this->ldapconn);
        return $userdata;
    }

    /*****************************************************************
     * FetchAllGroups()
     *****************************************************************/

    function FetchAllGroups() {
        $this->errormessage = null;
        $this->ldapconn = ldap_connect($this->ldaphost, $this->ldapport);

        if (!$this->ldapconn) {
            $this->errormessage = "Error: FetchAllGroups() could not get a connection to the LDAP Server";
            return FALSE;
        }
        
        $GroupsBase = "ou=Groups,".$this->basedn;
        $result = ldap_search($this->ldapconn, $GroupsBase, "(objectClass=*)");
        $data = ldap_get_entries($this->ldapconn, $result);
        ldap_close($this->ldapconn);
        
        return $data;
    }

    /*****************************************************************
     * FetchUserMembershipGroups()
     *****************************************************************/

    function FetchUserMembershipGroups($username) {
        $this->errormessage = null;
        // Calling user must already be logged in $this->ldapconn

        $GroupsBase = "ou=Groups,".$this->basedn;
        $result = ldap_search($this->ldapconn, $GroupsBase, "memberUid=$username");

        if(! $result){
            $this->errormessage = ldap_error($this->ldapconn);
            return FALSE;
        }

        $groupdata = ldap_get_entries($this->ldapconn, $result);
        return $groupdata;
    }
    /*****************************************************************
     * getRoles()
     *****************************************************************/
    function getRoles() {
        $groupdata = $this->FetchUserMembershipGroups($this->username);
        $groups = array();
         foreach($groupdata as $group){
             if ($group['cn'][0]){
             $groups[] = strtoupper ("ROLE_".$group['cn'][0]);
             }
         }
         return $groups;
    }

    /*****************************************************************
     * CheckGroupMembership()
     *****************************************************************/

    function CheckGroupMembership() {
        $this->errormessage = null;
        $this->ldapconn = ldap_connect($this->ldaphost, $this->ldapport);

        if (!$this->ldapconn) {
            $this->errormessage = ldap_error($this->ldapconn);
            return FALSE;
        }
       
        $GroupsBase = "ou=Groups,".$this->basedn;
        $result = ldap_search($this->ldapconn, $GroupsBase, "cn=Contractors");
        $data = ldap_get_entries($this->ldapconn, $result);
        ldap_close($this->ldapconn);
        return $data;
    }

    /*****************************************************************
     * FetchEntities()
     *****************************************************************/

    function FetchEntities($username, $password) {
        $this->errormessage = null;
        $dnusername = "uid=" . $username . ",ou=Users," . $this->basedn;
        $this->ldapconn = ldap_connect($this->ldaphost, $this->ldapport);

        if (!$this->ldapconn) {
            $this->errormessage = ldap_error($this->ldapconn);
            return FALSE;
        }

        $bindp = ldap_bind($this->ldapconn, $dnusername, $password);

        if ($bindp == false) {
           $this->errormessage = ldap_error($this->ldapconn);
            return FALSE;
        }
        $GroupsBase = "ou=Contacts,".$this->basedn;
        $result = ldap_search($this->ldapconn, $GroupsBase, "uid=*.0");
        $data = ldap_get_entries($this->ldapconn, $result);
        ldap_close($this->ldapconn);
        return $data;
    }

    /****************************************************************
     * CheckuserLogin()
     *****************************************************************/

    function CheckUserLogin($username, $password) {
        $this->errormessage = null;
        $dnusername = "uid=" . $username . ",ou=Users," . $this->basedn;

        $this->ldapconn = ldap_connect($this->ldaphost, $this->ldapport);
        if (!$this->ldapconn) {
            $this->errormessage = ldap_error($this->ldapconn);
            return FALSE;
        }
        $bindp = ldap_bind($this->ldapconn, $dnusername, $password);
        if ($bindp == false) {
            $this->errormessage = ldap_error($this->ldapconn);
            return FALSE;
        }
        return $bindp;
    }

    /*****************************************************************
     * Login()
     *****************************************************************/

    function Login($username, $password) {
        $this->errormessage = null;
        $dnusername = "uid=" . $username . ",ou=Users," . $this->basedn;

        $this->ldapconn = @ldap_connect($this->ldaphost, $this->ldapport);
        if (!$this->ldapconn) {
            $this->errormessage = ldap_error($this->ldapconn);
            return false;
        }

        $bindp = @ldap_bind($this->ldapconn, $dnusername, $password);

        if ($bindp == false) {
            $this->errormessage = ldap_error($this->ldapconn);
            return false;
        }
        
        $this->username = $username;
        $usersBase = "ou=Users,".$this->basedn;
        $result = ldap_search($this->ldapconn, $usersBase, "uid=$username");
        $userdata = ldap_get_entries($this->ldapconn, $result);
        $displayname = $userdata[0]['displayname'][0];
        $mail = $userdata[0]['mail'][0];
        $roles = $this->getRoles();

       // $user = new IpbrickldapUser($username, $password, NULL, $roles, $displayname,$mail );

        ldap_close($this->ldapconn);
        return array('username'=> $username,
                     'displayname' => $displayname,
                     'email'=> $mail,
                     'roles'=> $roles,
                     'otherdata'=> $userdata);
    }

}

Ok Now we need the FormLoginAuthenticator.php which will process the login form when the users attempts to login.

FormLoginAuthenticator.php which is a service, and referenced in security.yml as a knpuGuard Authenticator

namespace Trensys\EngineBundle\Security;

use KnpU\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;

class FormLoginAuthenticator extends AbstractFormLoginAuthenticator {

    // The symfony Police will flame you and send you to a skinny jeaned, mini driving
    // lumber jacked shirt, Starbucks drinking bearded hell.
    // Injecting the whole container causes tears in the space time continuum, You have been warned ! 

    private $container;

    public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container) {
        $this->container = $container;
    }

    // -------------------------------------------------------------------------

    public function getCredentials(Request $request) {
        //Fetch the submitted credentials from the login form
        //We could also include a nonce validation here to be extra secure

        if ($request->getPathInfo() != '/login_check') {
            return;
        }

        $username = $request->request->get('_username');
        $session = $request->getSession();
        $session->set(\Symfony\Component\Security\Core\Security::LAST_USERNAME, $username);

        $password = $request->request->get('_password');

        return array(
            'username' => $username,
            'password' => $password
        );
    }

    public function getUser($credentials, UserProviderInterface $userProvider) {
        //If we are here then we have some credentials. Here we are supposed to fetch
        // a user by the username supplied in the login form, However we do not want
        // a local user datbase in symfony, So what we do
        // (1) generate a fake non persistent one
        // (2) read the  ldap database using a LDAP Query and generate the user if it exits
        // and is enabled.
        //
        // Here we either handback a user or we don't (UserInterface Object)

        /*
         * A) If you return some User object (using whatever method you want) - then you'll continue on to 
         * checkCredentials().
         * B) If you return null or throw any Symfony\Component\Security\Core\Exception\AuthenticationException, 
         * authentication will fail and the user will be redirected back to the login page: see getLoginUrl().
         */

        $username = $credentials['username'];
        $password = $credentials['password'];
        $userProvider->setLdapPassword($password);
        return $userProvider->loadUserByUsername($username);
    }

    public function checkCredentials($credentials, UserInterface $user) {

        if(!$user->getStatus() == 'active'){
            throw new BadCredentialsException();
        }
        
    }

    protected function getLoginUrl() {
        return $this->container->get('router')->generate('trensys_engine_security_login');
    }

    protected function getDefaultSuccessRedirectUrl() {
        return $this->container->get('router')->generate('trensys_engine_security_welcome');
    }

}

Now we have all the required files, we need to do some plumbing to get all this stuff hooked up in Symfony.

Configure services.xml

services:
#    service_name:
#        class: AppBundle\Directory\ClassName
#        arguments: ["@another_service_name", "plain_value", "%parameter_name%"]
     app.form_login_authenticator:
        class: Trensys\EngineBundle\Security\FormLoginAuthenticator
        arguments: ["@service_container"]
     
     ldap_user_provider:
         class: Trensys\EngineBundle\Security\LdapUserProvider

Configure Security.yml

# To get started with security, check out the documentation:
# http://symfony.com/doc/current/book/security.html
security:

    encoders:
        # Our user class and the algorithm we'll use to encode passwords
        # http://symfony.com/doc/current/book/security.html#encoding-the-user-s-password
        AppBundle\Entity\User: bcrypt
        
    # http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
    providers:
        ldap_service:
            id: ldap_user_provider
        

    firewalls:
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        # Before production set some sensible firewall rules
        main:
            anonymous: ~
            # activate different ways to authenticate

            # http_basic: ~
            # http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate

            # form_login: ~
            # http://symfony.com/doc/current/cookbook/security/form_login_setup.html
            knpu_guard:
                authenticators:
                    - app.form_login_authenticator

With the plumbing done we now need a controller and a view to display the login form, and present the form again if the user fails to login (Don’t forget to review security.yml to suit your firewall needs)

Security Controller

namespace Trensys\EngineBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class SecurityController extends Controller {

    /**
     * @Route("/login")
     * @Template()
     */
    public function loginAction() {

       $helper = $this->get('security.authentication_utils');

        return array('last_username' => $helper->getLastUsername(),
            'error' => $helper->getLastAuthenticationError() );
    }
    
    /**
     * @Route("/logout")
     * 
     */
    public function logoutAction(){
        $this->get('security.token_storage')->setToken(null);
        $this->get('request')->getSession()->invalidate();
        $url= $this->generateUrl('trensys_engine_security_login');
       return  $this->redirect($url); 
    }
    /**
     * @Route("/login_check")
     * @Template()
     */
    public function loginCheckAction() {
        // will never be executed
        die('I should not have got here !');
        return array(
                // ...
        );
    }
    
    /**
     * @Route("/welcomelogin")
     * @Template()
     */
    public function welcomeAction() {
        
        $user = $this->getUser();
        
        return array('displayname'=> $user->getDisplayname());
    }

}

And here is our form/view. I will leave you to turn it into a form object with nonces etc.

login.html.twig based on a Bootstrap theme

< !DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Login</title>
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"/>
<!-- Bootstrap 3.3.4 -->
<link href="{{ asset('bundles/engine/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet" type="text/css" />
<!-- Font Awesome Icons -->
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<!-- Theme style -->
<link href="{{ asset('bundles/engine/dist/css/AdminLTE.min.css') }}" rel="stylesheet" type="text/css" />
<!-- iCheck -->
<link href="{{ asset('bundles/engine/plugins/iCheck/square/blue.css') }}" rel="stylesheet" type="text/css" />

<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
< ![endif]-->
</head>
<body class="login-page">
<div class="login-box">
<div class="login-logo">
<a href=""><b>Herber</b><br /> Intelligent Business automation</a>
</div><!-- /.login-logo -->
<div class="login-box-body">
<p class="login-box-msg">Sign in to start your session</p>
{% if error %}
<div class="alert alert-danger">
{{ error.messageKey|trans(error.messageData) }}
</div>
{% endif %}
<form action="{{ path('trensys_engine_security_logincheck') }}" method="post">
<div class="form-group has-feedback">
<input type="text" id="username" class="form-control" name="_username" value="{{ last_username }}" placeholder="Username" autocomplete="off" />
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
<input type="password" class="form-control" id="password" name="_password" />
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="row">
<div class="col-xs-8">


</div><!-- /.col -->
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">Sign In</button>
</div><!-- /.col -->
</div>
</form>
</div><!-- /.login-box-body -->
</div><!-- /.login-box -->

<!-- jQuery 2.1.4 -->
<script src="{{ asset('bundles/engine/plugins/jQuery/jQuery-2.1.4.min.js') }}" type="text/javascript"></script>
<!-- Bootstrap 3.3.2 JS -->
<script src="{{ asset('bundles/engine/bootstrap/js/bootstrap.min.js')}}" type="text/javascript"></script>
<!-- iCheck -->
<script src="{{ asset('bundles/engine/plugins/iCheck/icheck.min.js') }}" type="text/javascript"></script>
<script>
$(function () {
$('input').iCheck({
checkboxClass: 'icheckbox_square-blue',
radioClass: 'iradio_square-blue',
increaseArea: '20%' // optional
});
});
</script>
</body>
</html>

Ryan, thank you for KnpUguard, perhaps a proper dev can create a nice LDAPBundle :-)

I will update this post as I improve the integration, form objects, nonces etc.

Have fun !

reset local accounts on IPBrick

Posted on August 21, 2015
Filed Under IT Solutions | Leave a Comment

To reset the passwords on IPBrick (Debian) you will need to edit the default Grub menu at the boot screen.

Select the kernel and the Grub Boot screen and press e

Locate the kernel line of and enter

 init=/bin/bash 

at the very end.

press

 CTRL-X 

The server will then boot at drop you at the command prompt.

Enter the following to reset the passwords and reboot the server

mount -rw -o remount /
mount /usr
/usr/bin/passwd username

[ you will now be prompted to confirm and change the password]

shutdown -r -n now

The server will now reboot and you can login locally with the passwords you have just set.

Add new storage to your IPBrick

Posted on August 20, 2015
Filed Under IT Solutions | Leave a Comment

IPBrick creates 2 mount points on the file system for storage (/home1, /home2). You can add further storage locations (IPBrick refers to them as work areas) using a provided script.

ipbrick:/opt/system/scripts# php system_add_new_workareas.php X

X refers to the number of extra work-areas you want defined.

Before running this script you must have already created the mount point, formatted the disc and placed the disc in /etc/fstab. You must refer to the multipath mapper device to mount the storage see blkid command

The script only places the work area under the management of IPBrick. This means you can add additional hard discs SAN LUNS, DRDB block devices etc, and then present them to IPBrick for management.

Screenshot showing add work areas script

Asterisk Comedian Mail menu map

Posted on August 19, 2015
Filed Under IT Solutions | Leave a Comment

Asterisk Voicemail

Asterisk Comedian Voicemail menu map

Configure UK console keyboard on IPBrick

Posted on August 19, 2015
Filed Under IT Solutions | Leave a Comment

When you first login to your IPBrick console , You will find that the keyboard mappings will not match the UK keyboard.

Enter this command once you login:

ipbrick:~# dpkg-reconfigure console-data

Follow the onscreen menus and select the correct keyboard and language layout.

You only have to perform this once.

Configure QOS on your IPBrick

Posted on August 18, 2015
Filed Under IT Solutions | Leave a Comment

QOS (Quality of Service) is a hack or work around if you do not have enough bandwidth to deploy delay sensitive applications such as voice. QOS can buy you sometime whilst you sought out your bandwidth problems.

QOS has to be configured and deployed through the whole network for it to work ( Handsets, switches, routers etc).

https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service

To configure a IPBrick to tag packets with the recommended layer 2 and Layer 3 markers, Edit the following file

;Main file for manual changes to
; /home1/_AsteriskConfs/sip_main.conf

tos_sip=cs3
tos_audio=ef
tos_video=af41
tos_text=af41
cos_sip=3
cos_text=3
cos_video=4
cos_audio=5

Note: This will only affect asterisk, You may still see SIP signalling tagged as COS 4. This will be the kamaillo proxy. I’m not sure where to find the setting to match to cs3 instead. You could do cos mapping on your switch instead.

How to Backup Your IPBrick

Posted on August 17, 2015
Filed Under IT Solutions | Leave a Comment

IPBrick 6.1  has 4 key areas where data is stored

*/home1 is a very important area. It shares this mount point with user data and system data. If your IPrick is very busy will be beneficial if you mount this area to a SAN with ample discs and IOPS

IPBrick has a number of housekeeping activties it performs at 00:30 each night. It dumps out all database’s into /home1/backupSYS. These are the files that you should include in your file backups so you can restore your system case of total failure. (Please keep your other system conf change control files safe)

You have no control over the frequency of these database backups. This means even if you perform file system backups every hour, your database dump will always be dated at 00:30. You can perform a database dump of your user database files at any time you want

I suggest running filebackups to a External NAS using NFS or a SMB share or a USB drive mounted on the IPBrick.
IPBrick 6 uses Multipath by default, When connecting hard drives , LUNS and block storage you will need to identify the device using its UUID and /dev/mapper name.

eg:
ipbrick:/usr/local/bin# blkid
/dev/mapper/350024e92018c3aeb-part1: UUID="4882d6ff-875d-4044-bab8-e52082b68e5a" SEC_TYPE="ext2" TYPE="ext3"
/dev/sdd1: LABEL="backups" UUID="52a1d002-1fa9-4d0d-a918-2b71da70320e" SEC_TYPE="ext2" TYPE="ext3"
/dev/mapper/35000000000000001-part1: LABEL="backups" UUID="52a1d002-1fa9-4d0d-a918-2b71da70320e" SEC_TYPE="ext2" TYPE="ext3"

Use Rsnapshot to create snapshots backups of hourly,weekly,monthly and yearly. Rsnapshot is very efficient with disc space, and I suggest running this every 4 hours.

The system database is a protected database managed by the ipbrick itself. To perform more regular backups of the system dbdoc database you will need a special script from IPbrick called ipbrickdb_ip6. This script can be used to dump the database to keep to your file system BEFORE rsnapshot runs

Usage:

./ipbrickdb_ipb6  --dump --dbname dbdoc          --file /home1/_work/dump_dbdoc.sql

or
./ipbrickdb_ipb6  --restore --dbname dbdoc          --file /home1/_work/dump_dbdoc.sql

Within /etc/rsnapshot.conf tell rsnapshot to run this command BEFORE it peforms your backup by setting the path to this script in the following section

cmd_preexec /usr/local/bin/ipbrickdb_ipb6  --dump --dbname dbdoc          --file /home1/_work/dump_dbdoc.sql

Kdenlive video editor missing effects

Posted on January 23, 2015
Filed Under Open Source | Leave a Comment

 

http://superuser.com/questions/831700/how-to-get-the-missing-effects-on-kdenlive

 

sudo apt-get install frei0r-plugins gnome-video-effects-frei0r

 

Hope it helps

SMB Ethernet Switches. Save now, Pay Later

Posted on November 13, 2013
Filed Under Networking | Leave a Comment

We are all familiar with the “Small Business” range of Information Technology products. They are the crippled versions of the Enterprise range of products for grown up big business.

Manufacturers work hard to remove or disable features so they can sell products to “Small Business” at a lower cost. As small business owner this is appealing as you need to watch your capex and opex costs. Running a small business is not easy.

So you buy your small business switches, because they are cheaper than the big boys switches.

However as you use these switches they become a source of pain. This is because although you are a small business, You still need 802.1x port security , DHCP Snooping, 802.1q trunking, Jumbo Frames, flow control, Qos, LACP aggregation etc etc.

The reason for this is because small business’s are now using smaller versions of Enterprise functionality.

Small business’s are using virtualisation, Voice Over IP, Wireless Mobile devices, Network attached storage and Video Conferencing.

This technology is no longer the area of just Enterprise big business.

Over the past years a few manufactures have realized this and started to produce feature rich affordable switches which have small business pricing but enterprise features.
Take for example the switch pictured in this post.  This is a Zyxel 1910-48  Gigabit Switch. It cost the measly price of £240.00 ex VAT. ( I did mention this is a 48 port GIGABIT switch)

It is a layer 2 Access layer switch but it has everything you could need to deploy a VOIP, security, virtualisation or streaming project.

Show me any other Small business “Smart” switch which has this functionality.

It is quite simple, DON’T Buy fisher price “Small Business” switches because, that will be a very stupid thing to do ! You might think you are saving money, but you will pay later. Buy a Zyxel instead

zyxel 1910 48 port

Standard Compliance

Traffic Management and QoS

Class of Service (CoS)

Resilience and Availability

Security

Layer 2 Multicast

IPv6

Discovery

Network Management

MIB Information

Certification

BYOD Bring Your Own Desk

Posted on September 11, 2013
Filed Under Humor | Leave a Comment

Bring Your Own Desk

Bring Your Own Desk

There are a number of assets required which as a business owner you have had to supply your staff to enable them to work effectively. Your facilities management department actually spend a large amount of time purchasing and maintaining office furniture to enable your staff to work in a productive manner.

Even after all this work your staff may be dissatisfied with the standard you have chosen and look for alternatives. Since the consumerisation of office furniture from vendors such as ikea and costco, most employees now have access to a wide range of office desks which they wish to use at work.

Many of your staff will have office desks at home where they would like to able to be productive and some may even bring their desks to work to create a more comfortable working environment.

The challenge here is that the facilities management have been unable to support this. Having a standard desktop allows the facilities management to effectively plan office space, run the cabling infrastructure and maintain the keys to the desk drawers to ensure that the documents and items stored in the desk drawers are kept secure.

Rather than cause tension between the facilities management, and possibly reduce the productivity of your staff, it is best to define your BYOD policy.

There are a number of new innovations to enable staff to use BYOD and allow facilities to cover some of the security risks and office space challenges.

According to a survey by ikea 71% of staff will be willing to pay for their own office desk for use for work.

There are some key opportunities for business’s to make big savings for facilities management. The key risks which you need to plan for is the management of item loss by staff using keys, and for the business owner to be able to manage desk content when the member of staff leaves the company or the desk is stolen.

There are a number of vendors which have a BYOD policy and can help you minimise these risks

www.ikea.com

keep looking »
rss xml image rss xml image