Midgard1

Web Content Repository for PHP

Midgard1 8.09 Ragnaroek LTS is a Long Term Support version of Midgard1 for which bug fixes and minor feature improvements will be supplied by the Midgard community until October 2012. It is recommended that all Midgard1 users upgrade their installations to the Midgard 8.09 series for stability, performance and maintainance reasons. Upgrade from MidCOM 2.8 installations running with PHP5 has been made as seamless as possible.

The version is targeted to ease transition from web services using the deprecated Midgard1 APIs to the new Midgard2 architecture. Because of this, the Ragnaroek series provides both API versions. This means that the release can be used to run both Midgard1 applications like the MidCOM component framework and OpenPSA, and Midgard2 applications like Midgard MVC.

Want to learn about the migration path to Midgard2? Read the Modernizing MidCOM post.

Downloads

Ubuntu

On Ubuntu Lucid (10.04 LTS), run the following command:

$ sudo add-apt-repository "deb http://download.opensuse.org/repositories/home:/midgardproject:/ragnaroek/xUbuntu_10.04/ ./"

Then just install Midgard1 via apt-get update and apt-get install midgard-data. After this completes you can set up the system with Datagard.

Debian

On Debian Squeeze, add the following to your /etc/apt/sources.list:

deb http://download.opensuse.org/repositories/home:/midgardproject:/ragnaroek/Debian_6.0/ ./

On Debian Lenny, add the following to your /etc/apt/sources.list:

deb http://download.opensuse.org/repositories/home:/midgardproject:/ragnaroek/Debian_5.0/ ./

Then just install Midgard1 via apt-get update and apt-get install midgard-data. After this completes you can set up the system with Datagard.

Datagard

atagard is the command-line tool for managing Midgard installations. After you have installed the Midgard1 packages on your system you can use it for setting up the Midgard environment.

Basic and easiest setup can be done by just running datagard command. Datagard will ask you questions, and guide you step by step through setup process.

Datagard will do the following operations for you:

  • Set up a Midgard1 MySQL database
  • Create a new Apache virtual host to be used with Midgard
  • Install and set up a MidCOM environment

Command line options

-t type of the setup

Type of the setup:

  • quick, datagard tries to determine sensible defaults for all configurations (this is usually a good choice for upgrades as then datagard reads the settings from the configuration file)
  • wizard (the default if you don't specify type), datagard asks about every single configuration option

-c file

Specifies user defined configuration file name (the default is midgard if you leave out -c) -a <action> Action type selection. Possible actions are:

  • install, the default if you don't specify action - installs the database and the Midgard PEAR packages, and then creates a virtual host
  • upgrade, upgrade the database and the MidCOM PEAR packages<
  • vhost, create a new virtual host. This operation requires that the database contains a style template for the vhost. Style templates are imported to the db during the install action
  • dbinstall, install a new database and its configuration file. Remember to specify the database name using the -c option if you already have a database called midgard. Keep in mind that this action doesn't import style templates to the db like the install action does
  • dbupdate, update the database structure
  • pear, install/upgrade Midgard PEAR package(s). Needs Midgard version to be at least the same as the version of the PEAR packages, because the database structure isn't updated beforehand
  • sitegroup, create a new domain/sitegroup

-p package name

Install a given application or component.

When installing a new site with application like OpenPSA:

# datagard -a install -p openpsa

When installing/updating new component like midcom_helper_search to an existing Midgard CMS installation:

# datagard -a pear -p midcom_helper_search

-v level

Sets verbosity level, numeric option. The default value is 0

Sitegroups

Sitegroups provide a method of hosting multiple organizations within one Midgard installation.

Every record in the database is tagged as belonging to a specific sitegroup. The effect is much the same as storing sites for separate clients in separate databases in that resources can't be accessed across Sitegroups and has the following benefits:

  • Sitegroups reduce the number of persistent database connections. When storing hosts in distinct databases, each Apache handler process opens a persistent connection to every database. It is not unusual to have 20-30 handler processes active per Host. Which, when multiplied by the number of clients, surpasses the default MySQL configuration for 100 connections.
  • One special Sitegroup, Sitegroup 0 (SG0), is read-only for all other Sitegroups and merges transparently with any other Sitegroup. You can therefore install one single administration interface that is available to all while still maintaining the separation between several sites. Also, upgrades to the administration interface will immediately be available to everybody.
  • You can grant separate administration privileges for each Sitegroup.
  • You can easily limit the Disk Quota and number of allowed MgdSchema objects of a specific type for each Sitegroup
  • Sitegroups and websites are easy to create using the Midgard Site Wizard

Sitegroups account for three categories of Midgard users depending on their access level:

  • Root level users ( Root users) have full access to every resource within every Sitegroup, including SG0.
  • Admin level users ( Administrators ) have almost full access to every resource in one Sitegroup. They may be seen as sites administrators, although there may be several sites in one Sitegroup.
  • User level users ( Users ), whose privileges are described in documentation

The Administrator Group: root level users

Any member of the Group 0 is a root level user ( Root user ) , which means he can do anything on the system. Only server administrators should be members of that Group, as everything else can be handled by creating a proper Group system.

Only root level users can:

  • Modify shared Midgard applications like templates, which belongs to SG0.
  • Create new Sitegroups.
  • Create new Hosts ; or modify the name, prefix and port fields of an existing Host record.

Admingroups: admin level users

Any member of the group whose id equals the admingroup field of a Sitegroup record is an admin level user ( Administrator ) for that Sitegroup. This means he has write access to every resource within that Sitegroup but the name, prefix and port fields of the Host table.

Only admin level users can modify Host records (apart from the three above mentioned fields): They can choose whether the sites within their Sitegroup are online, and whether they require authentication.

Also, only they can create root Pages, root Styles and root Topics.

Login Delimiters

A root or admin level user may want to limit his rights when doing a specific task which doesn't require special privileges, or so as to check on a user's rights. This is achieved by authenticating with a username and a Sitegroup name, separated with a Delimiter.

Sitegroup login Delimiters for root level user root

Case Login level Delimiter Login
1 root none root
2 root * root*sitegroup
3 admin ! root!sitegroup
4 user $ root$sitegroup
5 user =, $ root=user$sitegroup
  1. root is logged in SGO. He has full access to all Sitegroups, but anything he creates will be part of SG0 only.

  2. root is logged in sitegroup. He has full access to all Sitegroups, but anything he creates will be part of sitegroup only.

  3. root has the same privileges as admin.

  4. root is logged in as a user, but looses all his write privileges as he doesn't belong to any Group.

  5. root is logged in as user with root's password. He gets the same privileges as user.

Sitegroup login Delimiters for admin level user admin

Case Login level Delimiter Login
1 admin + admin or admin+sitegroup
2 user ; admin;sitegroup
3 user = (, +) admin=user or admin=user+sitegroup
  1. admin is logged in as admin.

  2. admin is logged in as a user, and looses all his privileges as he doesn't belong to any Group.

  3. admin is logged in as user with admin's password. He gets the same privileges as user.

Sitegroup login Delimiters for user level user user

Case Login level Delimiter Login
1 user + user or user+sitegroup
  1. user is logged in as user.

Storage quotas

With Midgard Quota, you can define per-sitegroup restrictions on

  • the number of records for each table
  • the maximum content size in each table, where you can define which fields count as content
  • the maximum size for attachments.
  • the maximum content size for all objects of a sitegroup.

If you try to create / update a record, and the quota for the table is reached, error MGD_ERR_QUOTA (Quota reached) is triggered.
The same happens if you open an attachment and the maximum attachment size is reached.

As of Midgard 1.7, the Quota features are set up automatically. It is also good idea to make database update using datagard with every new Midgard release installed.

Configuration

Apache configuration directive:

MidgardCheckQuota (On|Off) default: Off  

Quota limits will be checked for every object created or updated with VirtualHost which uses this directive set to On. Alternative option is mgd_check_quota function which may be used per request without any need to reload httpd server when configuration should be changed and quota limits check shouldn't be defined globally.

Initialization

<?php

$sgid = 1234;

$q = new midgard_quota();
$q->sg = $sgid;  /* Required for legacy quota */
$q->typename = ""; /* empty name is set for all types */
$q->tablename = "wholesg"; /* required for legacy quota */
$q->sgsizelimit = 1000; /* quota limit in bytes */
$q->space = 1000;  /* quota limits in bytes for legacy quota */
$q->spacefields = ""; /* deprecated but required by legacy quota */
$q->number = 0;  /* legacy quota */

/* Midgard 1.8 */
/* $q->sitegroup = $sgid;*/

$q->create();

/* Midgard 1.7 */ 

$q->sitegroup = $sgid;
$q->update();

?>

Midgard Quota API functions

  • mgd_check_quota - Initialize quota check for current request
  • mgd_create_quota - Creates quota limits entry for defined sitegroup
  • mgd_list_quotas - List quota records
  • mgd_get_sitegroup_size - Returns sitegroup's disk usage size.
  • mgd_update_quota - Update quota record
  • mgd_delete_quota - Delete quota record
  • mgd_get_quota - Get quota object

MidgardQuota object

 class Quota
 {  
      var $id;  
      var $sitegroup; // sitegroup   
      var $tablename; // table or special name 'blobsdata' for           
                      // filesystem blobs or special name  
                      // 'wholesg' for all objects of the SG  
      var $spacefields; // the fields that count as content 
                        // for this table  
      var $number; // max number of records  
      var $space; // max length of content fields or max disk 
                  //space for filesystem blobs (both in KB)  
      var $eff_number; // effective number of objects for 
                       //which this quota is defined  
      var $eff_space; // effective size of objects for which 
                      // this quota is defined  
 }   

Example

 /* as $midgard->root: */  

 /* The total size of all content fields of table page_i may      not exceed 1000 KB for sitegroup $sg */  
 mgd_create_quota($sg, 'page_i', 'content', 0, 1000);   

 /* The total size of all value fields of table pageelement_i may not exceed 1000 KB for sitegroup $sg */  
 mgd_create_quota($sg, 'pageelement_i', 'content', 0, 1000);  

 /* The total size of all content & abstract fields of table article_i may not exceed 1000 KB for sitegroup $sg */  
 mgd_create_quota($sg, 'article_i', 'content,abstract', 0, 1000);  

 /* The total size of all value fields of table element_i may not exceed 1000 KB for sitegroup $sg */  
 mgd_create_quota($sg, 'element_i', 'value', 0, 1000);  

 /* The total size of all code fields of table element_i may not exceed 1000 KB for sitegroup $sg */  
 mgd_create_quota($sg, 'snippet_i', 'code', 0, 1000);  

 /* The total size of all extra & pgpkey fields of table person may not exceed 1000 KB for sitegroup $sg */  
 mgd_create_quota($sg, 'person', 'extra,pgpkey', 0, 1000);   

 /* The total size of all attachments may not exceed 10000 KB for sitegroup $sg */  
 mgd_create_quota($sg, 'blobsdata', '', 0, 10000);  

 /* The total size of all table fields and blobs data defined above may not exceed 10000 KB for sitegroup $sg */  
 mgd_create_quota($sg, 'wholesg', '', 0, 12000);  

 /* The total number of articles may not exceed 1000 for sitegroup $sg */  
 mgd_create_quota($sg, 'article', '', 1000, 0);  

 /* ... */  
 /* as normal user: */  

 $qinfo = mgd_get_quota_info_by_tablename('blobsdata');  
 $qinfosg = mgd_get_quota_info_by_tablename('wholesg');  

 /* Test if file $filename could be written into an attachment      according to quota rules */  
 if ($qinfo->eff_space + (filesize($filename) / 1024) >=  $qinfo->space or $qinfosg->eff_space + (filesize($filename) / 1024) >= $qinfosg->space) {   
      echo "File too big";  
 }

MgdSchema and multilingual content

Midgard's multiLang system provided for MgdSchema objects supports creating and serving same content in different languages quickly and easily. MultiLang types can be freely defined using Midgard schema files.

The main advantage of ML content for schema objects is its transparent usage. There are few important rules:

  • Every object always has default lang content.
  • ML is optimized for translations
  • Content is always "served" in language context.
  • Language and DefaultLanguage are always defined as global values

Create language context

Content with default lang is always accessible and is fully transparent for other languages. When object has content in many different languages then languge content take precedence over default lang . If object has no content for currently used lang then default lang content is returned.

Creating language content

Particular language content for object is almost like translation. Any new object is not created , but instead only language content for currently existing object is created. To create language content you should at least set application's language using mgd_set_lang function and get already exising object.

Let's assume that default content is created in Polish and English translation should be added.

Application is running and language is set to Polish (default language).

$lang = 52; /* English language id*/
$id = 1234; /* Object's id */

Global translation language should be changed. After this change appllication is running in English translation language context.

$mgd_set_lang($lang); 

Object is fetched from database. There is no English translation yet, so object with default lang (Polish) content will be returned.

$object = new midgard_article($id); 
echo $object->title;    

The output is "Witaj świecie!"

$object->title = "Hello World!";
$object->update();

English language content is created. Now it's possible to change language at any time.

mgd_set_lang($polish_lang_id);
$object = new midgard_article($id);    

echo $object->title;
echo "in English language means: "

mgd_set_lang($lang);
$object->get_by_id($id);

echo $object->title;  

The output:

Witaj Swiecie! in English means Hello World!

MgdSchema metadata

midgard_metadata is internal class registered in midgard-core and also registered as internal php class in midgard-php extension. It is registered as member of every class available during runtime and defined in Mgdschema file. MgdSchema object's property which is a pointer to midgard_metadata object is called metadata.

Note: This object has no defined methods.

midgard_metadata class members

creator read-only
holds string value with guid of a person who created object. This property can not be set from application level. It's internally overwritten , even if it is set by user.

created read-only
holds ISO 8601 formatted date string value. This property value is set only once when object is created, and can not be overwritten by client application.

revisor read-only
holds string value with guid of a person who updated object. This property can not be set from application level. It's internally overwritten , even if it is set by user. When object's record is created a value of this property is equal to creator property. When update method is invoked then value of property is equal to the guid of person who updates object.

revised read-only
holds ISO 8601 formatted date string value. This property value is set every time when object is updated. It's internally overwritten , even if it is set by user. When object's create method is called value of this property is equal to created property value.

revision read-only
holds integer value. This property value is set and increased every time when object is updated. It's internally overwritten , even if it is set by user. Default value of this property is 0 when object is created, and is increased by 1 with every update method call.

locker holds string value with guid of a person who updated object. This property can be set from application level. A caller is responsible to set value with correct guid.

locked holds ISO 8601 formatted date string value. This property can be set from application level. A caller is responsible to set value with correctly formatted date.

approver holds string value with guid of a person who updated object. This property can be set from application level. A caller is responsible to set value with correct guid.

approved holds ISO 8601 formatted date string value. This property can be set from application level. A caller is responsible to set value with correctly formatted date.

authors
holds longtext value. You should pay special attention while setting this property. There is no clear convention about how this property should be set.

owner
holds string value with guid of a person who updated object. This property can be set from application level. A caller is responsible to set value with correct guid.

schedulestart holds ISO 8601 formatted date string value. This property can be set from application level. A caller is responsible to set value with correctly formatted date.

scheduleend
holds ISO 8601 formatted date string value. This property can be set from application level. A caller is responsible to set value with correctly formatted date.

hidden
holds boolean value. This property can be set from application level.

navnoentry
holds boolean value. This property can be set from application level.

size read-only
holds integer value. Value of this property is total storage usage size of an object ( in bytes ). Additional bytes needed by database server storage are also added to size value. When object is midgard_attachment type , size of file is added to size.

score holds integer value. Score is an editable integer that can be for example used for sorting Query Builder results.

published
holds ISO 8601 formatted date string value. This property can be set from application level. When object's create method is called value of this property is by default set to created ones value. A caller is responsible to set value with correctly formatted date.

deleted read-only
holds boolean value. This property is set internally by midgard-core. In every case is set to FALSE, except retrieving deleted objects.

exported read-only
holds ISO 8601 formatted date string value. This property is set internally by export method. Its value is a datetime value when object has been exported from database.

imported read-only
holds ISO 8601 formatted date string value. This property is set internally by import method. Its value s a datetime value when object has been imported to database.

Datetimes

Every ISO 8601 formatted date is stored in UTC timezone. Timezone qualifier is defined in datetime string, however it may be ignored by some database engines. (MySQL for example ignores timezone qualifier but stores datetime in UTC).

When object's record is retrieved from database , datetime is not converted to local timezone. And datetime string is retrieved "as is".

Client application is responsible to convert datetime to local timezone. Or to convert datetime to any other format if needed. When property value ( with MGD_TYPE_TMESTAMP type) is incorrectly set or converted to ISO 8601 datetime format, then database storage engine converts such value to default unset datetime: 0000-00-00 00:00.

An empty string is set as property value if datetime is not set for property which holds MGD_TYPE_TIMESTAMP value type. Such value is easy accessible with simple 'if' condition:

<?php
if ($object->metadata->schedulestart)
{
    echo "Published since $object->metadata->schedulestart";
}
?>

Datetimes in MidCOM

The MidCOM DBA system modifies datetime handling so that all metadata datetime properties can be used as Unix timestamps instead of strings.

<?php
// Set the article's publication time to NOW
$article->metadata->published = time();
$article->update();

// Echo article's approval time
$approval = strftime('%x %X', $article->metadata->approved);
echo "Article was approved on {$approval}.";
?>

Example

<?php
$guid = "f6b665f1984503790ed91f39b11b5392";

$parameter = new midgard_parameter();

if($parameter->get_by_guid($guid)) 
{

    echo "Parameter with $parameter->guid was 
         created: $parameter->metadata->created"; 
}
?> 

*Note:** to query object with metadata properties use MidgardQueryBuilder with metadata.propertyname as constraint. The same syntax is used when ordering by metadata property is needed

Kerberos single sign-on with Active Directory

Kerberos authentication is a third party authentication mechanism supported by Midgard. It allows users to log in to Midgard using their LDAP or Active Directory accounts. In Kerberos authentication users may log in to Midgard in the normal way or using single sign-on method.

Basic kerberos configuration on midgard server

Install mod_auth_kerb.

Configure /etc/krb5.conf

[libdefaults]
    default_realm = KERBEROS.REALM

[domain_realm]
    apache.server.fqdn = KERBEROS.REALM

[realms]
    KERBEROS.REALM = {
        kdc = kdc.kerberos.realm
        }

Test configuration

$ kinit username
$ klist

If you get ticket from the kerberos server, you should be fine to continue. Otherwise you might find the troubleshooting section, in the end of this document, useful.

Creating keytab for single sign-on

First you must create a user account on the kerberos domain controller server. The user account must not be disabled and the password must stay the same. Otherwise you might need to recreate the keytab. In this example the user account name is "apache_server" and has password "apache_password".

Windows Server 2003:

C:\Program Files\Support Tools>ktpass -princ HTTP/apache.server.fqdn@KERBEROS.REALM -mapuser apache_server -crypto DES-CBC-MD5 -ptype KRB5_NT_PRINCIPAL -mapop set +desonly -pass apache_password -out name.keytab

Windows Server 2000 (not tested):

C:\Program Files\Support Tools>ktpass -princ HTTP/apache.server.fqdn@KERBEROS.REALM -mapuser dummyuser -crypto DES-CBC-MD5 -pass password -out name.keytab

Install support tools to optain ktpass.exe. After creating the keytab you propably need to reset the password because of the new crypto type. You need to use the same password.

apache.server.fqdn = the site url you are going to use. The url must be resolvable by the kerberos and midgard server to the midgard server ip-address.

Place the keytab file on the midgard server and give apache user read rights to the file.

Test the keytab:

$ kinit -k -t /etc/name.keytab HTTP/apache.server.fqdn
$ klist

If you get ticket from the kerberos server, you should be fine to continue. Otherwise you might find the troubleshooting section, in the end of this document, useful.

Configuring midgard vhost

Below is a configuration for a kerberos SingleSignOn authentication which fallbacks to a kerberos password authentication.

Servername apache.server.fqdn
MidgardAuthType trusted

<Location "/">
    AuthName "Kerberos Authentication"
    AuthType Kerberos
    KrbAuthRealms KERBEROS.REALM
    Krb5Keytab /etc/name.keytab
    KrbMethodNegotiate on
    KrbMethodK5Passwd on
    Order Allow,Deny
    # Allow cron scripts etc from local machine
    Allow from localhost
    Allow from apache.server.fqdn
    # Require kerberos for others
    Require valid-user
    Satisfy any
</Location>

Browser support for single sign-on

Firefox:

Go to about:config edit network.negotiate-auth.trusted-uris and add http(s)://(site)

IE6:

Add the site to trusted sites. Make sure that "Enable Integrated Windows Authentication" is on

Troubleshooting and useful links

In midgard server the site url must be /etc/hosts as a first entry for the ip in question:

172.0.0.1       locahost.localdomain localhost
'ip-address'    apache.server.fqdn apache

The midgard server must be in same time with the kerberos server. You can use ntp or ntpdate for this.

GSS failure "Key version number for principal in key table is incorrect"

If you reset the password after creating the keytab you will need to create a new one, even if kinit does not complain the Kerberos server will refuse to serve authentication requests for the "old" keytab.

Links: