Showing posts with label opengroupware. Show all posts
Showing posts with label opengroupware. Show all posts

2010-12-08

Manually Adding an ACL To An Object

In OpenGroupware the ACLs applied to an object are stored in the "object_acl" table.  If, for example, I want to add the list, view, read, write, and administer privileges for the team 11,530 for object 1,6829,810 the correct SQL to execute is:
INSERT INTO object_acl
  (object_acl_id, sort_key, action, object_id, auth_id, permissions)
VALUES (nextval('key_generator'), 0, 'allowed', 16829810, 11530, 'lvrwa')
The important points are:
  1. Use the "key_generator" sequence to assign the "object_acl_id" value.  This is the object id of the ACL itself;  all object ids are assigned from the key_generator sequence.
  2. The value of "sort_key" is always 0.  This value isn't actually used for anything.
  3. The value of "action" must be either "allowed" or "denied".  In most cases "allowed" is what you want in order to grant access.
  4. "object_id" is the object id of the object to which the ACL is applied in contrast to "auth_id" is the context to which the privileges, specified in "permissions", are either granted [if "action" is "allowed"] or revoked [if "action" is "denied"].  The value of "auth_id" should be the object id of an account or a team.
  5. The permissions string is always lower case.  Permission flags are documented in WMOGAG.
The ACLs in "object_acl" are the primary access control mechanism for all entities excepting Projects and Appointments.

2010-07-26

Bootstrapping "opengoupware.us"

Thanks to the addition of the "pages" feature in Blogspot I've finally created a site at opengroupware.us, The OpenGroupware [Legacy] project website (I won't even bother to link to it) has been worthless for some time, and the information about the constellation of projects beyond legacy is very scattered. opengroupware.us is an attempt to at least create an index of that information as well as resurrect some of the good content from the abyss that is the docs plone.  If you want to submit content to opengroupware.us or want to help edit / maintain content just let me know any I'll add your Blogspot account to the site permissions.

2010-01-21

Python Curses In Action, even on AIX.


So, what if you have an old COBOL application that you want to integrate with some web services or a website? You'd need a "green-screen" application that can take that COBOL applications temporary output file, send it up to the web service, wait for a response, replace the temporary file, and then return control to the COBOL application (or whatever "green screen" application comes next). It sounds simpler than it is in practice: what if the web service takes awhile to complete [or has human involvement on the other end?!] or the web service isn't available right at the moment you try to send your request? For a real production environment your "green screen" application would need to deal with all of those things.
And you need that "green screen" application to work on both LINUX and AIX!


Fortunately pware provides Python 2.6 for AIX, including curses! The curses library and respective Python module provide a surprisingly easy way to create professional looking TUI (Text User Interface) applications like the solution required in our example. This particular application takes them temporary file and submits it via a WebDAV PUT operation to the workflow engine provided by OpenGroupware Coils. The route in the workflow engine reformats the dreadful output of the COBOL application into the required format (using the format support in route Read and Write operations). The client detects the route is complete by watching the URL specified in the header of the initial PUT, and then downloads the required data. If anything goes wrong along the way the client can retry, or provide the user the option to abort. All along the way the client provides detailed feedback to the user and a familiar dialog-box and prompt interface when feedback is required.

2009-07-26

Service BASIC HTTP Authentication with Python

While building the core parts of OpenGroupware COILS I noticed there don't appear to be any example of providing HTTP's BASIC authentication scheme anywhere on the interweb. Or any other authentication schemes for that matter. To remedy that here is a rough outline, including the example code, of how it is implemented in COILS. First spin up an HTTP server:

import BaseHTTPServer

class HTTPServer(BaseHTTPServer.HTTPServer):
pass

from coils.net.handler import HTTPRequestHandler
from coils.net.server import HTTPServer
....
HTTP_HOST = 'localhost'
HTTP_PORT = 8080
httpd = HTTPServer((HTTP_HOST, HTTP_PORT), HTTPRequestHandler)
httpd.serve_forever()

Your app will almost certainly provide a custom HTTPRequestHandler to delegate the requests to whatever logic your application provides. In the BaseHTTPRequestHandler a GET request is handed to do_GET, a POST request to do_POST, etc... In our case the object that handles the request will decide what to do based on the request type so we channel all requests to our generic process_request method. process_request looks up the object targeted by the request via marshall_handler() [not shown] and then calls that objects do_request method. The important part for authentication is to catch the exception raised by the object handling the request if that object thinks the request is not authenticated and requires authentication. In this case that is the COILS' AuthenticationException; your application has to provide something equivalent. In order to make the client try again with authentication you need to send a "WWW-Authenticate" header telling the client to use basic authentication and what realm to use. See RFC2617 for details on Basic authentication in general

class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

def process_request(self):
"""Respond to a request"""
try:
""" find the object mapped to the specified request
The marshall_handler() is a COILS specific things so it isn't
shown in this example. """
handler = self.marshall_handler()
handler.do_request(self)
except AuthenticationException, err:
""" An AuthenticationException has an error code of 401
We need to add an authentication header so the client will know
to respond the the failure with the appropriate credentials
TODO: Provide a digest realm once digest authentication is supported
"""
self.send_response(err.error_code())
self.send_header('WWW-Authenticate', 'Basic realm="OpenGroupware COILS"')
self.end_headers()
self.wfile.write('Authentication failure')
except CoilsException, err:
# An Coils Exception has an error code of 500
self.send_response(err.error_code(), err.error_text())
self.end_headers()
except Exception, err:
# Yikes, something generic web very wrong
self.send_response(500, err)
self.end_headers()

def do_GET(self):
"""Respond to a GET request."""
self.process_request()

def do_POST(self):
"""Respond to a POST request"""
self.process_request()

In order to actually process the authentication request COILS uses an Authenticator object. Our DBAuthenticator object provides basic authentication against accounts with passwords stored directly in the database [verses accounts from LDAP or trusting an external authorization mechanism such as Kerberos]. Explanation for the steps to process a Basic authentication operation have been added to the code example:

from base64 import b64decode
from crypt import crypt
class DBAuthenticator(Authenticator):

def _authenticate(self, context, request):
Authenticator._authenticate(self, context, request)
authorization = request.headers.get('authorization')
if (authorization == None):
raise AuthenticationException('Authentication Required')
(kind, data) = authorization.split(' ')
if (kind == 'Basic'):
# Authentication method is "Basic"
(username, _, password) = b64decode(data).partition(':')
""" This method provided by the parent class goes to the ORM and
retrieves the account object for the specified username. It
will throw an authentication exception if no such username is
found (user entered it wrong?) or a generic Coils Exception if
multiple objects match the username (that doesn't make sense) -
either will stop the authentication process, but the authentication
exception should reprompt the client to try again. """
account = Authenticator._getLogin(self, username)
secret = account.password
if (secret == crypt(password, secret[:2])):
# Password matches, user is authenticated
self.loginId = account.objectId
self.login = account.login
else:
# Password does not match, authentication failes
raise AuthenticationException('Incorrect username or password')
else:
# Authorization header indicated an authentication type other than BASIC
CoilsException('Unsupported HTTP Authenticated Mech')


See, that easy easy.

2009-07-08

Database Changes to OpenGroupware v5.5

For those building from trunk, or currently pulling packages from OBS, there is a new table required as of r2256.


CREATE TABLE ctags (
entity VARCHAR NOT NULL,
ctag INTEGER NOT NULL DEFAULT 0
);
INSERT INTO ctags (entity) VALUES ('Person');
INSERT INTO ctags (entity) VALUES ('Enterprise');
INSERT INTO ctags (entity) VALUES ('Date');
INSERT INTO ctags (entity) VALUES ('Job');
INSERT INTO ctags (entity) VALUES ('Team');


This is part of adding ctag support to OGo (specifically ZideStore). ctags allow a client to *very* quickly detect if the contents of a collection have changed; such as the /public/Contacts folder. Thus avoiding doing a PROPFIND on the entire folder to determine if a re-sync is needing. ctag support is not complete or working yet, but without this table a server post-r2256 will fails some operations with a database error.


The subversion repository contains an update script for migrating a v5.4 database to v5.5.

2009-03-12

Bug#394

OpenGroupware revision 2181 closes Bug#394. It is now possible to set a default to determine the default storage backend for new projects. (Wow, with GNUstep based stuff one ends up using the term "default" so often in different ways....)

To select database as your default project storage backend:
Defaults write NSGlobalDomain OGoDefaultProjectStorageBackend Database

To select the filesystem as your default project storage backend:
Defaults write NSGlobalDomain OGoDefaultProjectStorageBackend FileSystem

Most people I assume will want "Database". Remember that default values are CASE SENSITIVE!

If you (at least on r2181) attempt to create a project without selecting FileSystem/Database you'll get a popup warning: "Please specify your project storage!" If the default is set then the preferred storage backend is preselected (and can be changed).

Aside: If you use FileSystem projects make sure you have the SkyFSPath default set and that the referred to directory has the correct permissions.

2009-03-04

Packages Complete

OpenGroupware packages have been completely built on the build service for CentOS5, Fedora 9, openSUSE 10.3, RHEL 5, and SLES10. The Fedora 10 and openSUSE 11.x packages needs some additional work.

Repositories at
:
Initial testing on CentOS 5 seems pretty positive, after a:
$ yum install ogo-meta ogo-database-setup

Only glaring bug is that ogo-database-setup doesn't actually populate the database schema so that still needs to be done by hand:


$ cat pg-build-schema.psql | psql -h localhost -U OGo OGo

Then restarting the services gives you [as far as I can tell so far] a fully working OGo install.

P.S. Make sure your getting the most current packages from the repository. mod_ngobjweb in particular should be dated March 4th; with the previous version the web resources (icons, etc...) for the WebUI won't be found at the configured path.

2009-01-04

Almost there

The ogo-meta package now almost installs on CentOS5 except that we don't have the ogo-environment or the ngobjweb packages. OpenSUSE 11.0 and 11.1 have some problems building anything beyond ogo-gnustep_make; OpenSUSE 10.3 builds up to the same point as CentOS5.


$ yum install ogo-meta
...
---> Package ogo-meta.i386 0:1.1-6.7 set to be updated
--> Processing Dependency: mod_ngobjweb for package: ogo-meta
--> Processing Dependency: ogo-environment for package: ogo-meta
---> Package postgresql.i386 0:8.1.11-1.el5_1.1 set to be updated
---> Package postgresql-libs.i386 0:8.1.11-1.el5_1.1 set to be updated
--> Finished Dependency Resolution
Error: Missing Dependency: ogo-environment is needed by package ogo-meta
Error: Missing Dependency: mod_ngobjweb is needed by package ogo-meta

2009-01-01

OpenGroupware Package Repositories

Currently working on getting OpenGroupware (and related GNUStep-make, SOPE, & ngobjweb) packages built of the Novell Build Service. Repositories at:

Not everything working yet, but getting there.

2008-09-21

OpenGroupware r2150 & RSS Feeds

As of r2150 OpenGroupware now supports the following RSS 2.0 feeds:
  • projectActions - Reports actions on tasks assigned to projects of which the user is a member either directly or via team membership.
    • http://opengroupware.mormail.com/zidestore/so/${USER}/Tasks/delegated-actions-rss
  • toDoActions - Reports actions on tasks of which the user is an executor either directly or via team membership.
    • http://opengroupware.mormail.com/zidestore/so/${USER}/Tasks/project-actions-rss
  • delegatedActions - Reports actions on tasks created by the user.
    • http://opengroupware.mormail.com/zidestore/so/${USER}/Tasks/todo-actions-rss
By default the 150 most recent task actions are included in the feed; this value can be adjusted by including a "limit" value in the URL.

2008-03-05

getAuditEntries added to zOGI r2095

The getAuditEntries method was added to the zOGI API as of r920, and added to the ZideStore trunk in r2095. getAuditEntries provides the ability to retrieve the audit entries from the server's database that have occurred since a specified entry. Using this feature a service can page through server changes and synchronize some repository; this allows functionality equivalent to that provided by MOGIMon but without a back-door database connection. Since audit records are serialized with integer ids in the OpenGroupware database this acts very much like the uSNChanged attribute provided by Microsoft Active Directory.

2006-12-19

openSUSE 10.2 & gcc-objc

Neither the openSUSE 10.2 CDs nor the DVD image contain the the gcc-obj or the libobjc packages required to compile and run Objective-C applications such as OpenGroupware. I'm led to believe that the commercial DVD does contain more packages as it is multi-layered.

Fortunately this oversight is easily remedied; you just need to add the online package repository as an installation source. Go into YaST / Software / Installation Source, then add an HTTP source with a "Server Name" of "download.opensuse.org/distribution/10.2/repo/oss/". This is the default package repository for all Open Source packages provided with openSUSE 10.2. Clicking "Next" will then cause YaST to thrash around for awhile as it downloads what it needs to support the installation source. After prompting for acceptance of the same license agreement you accepted when installing the distribution the channel should be available.

Searching in Software / Software Management you should now find three Objective-C related packages: gcc41-objc, gcc-obj, and libobjc41. Only the latter is required to run Objective-C applications.

Once libobjc41 is installed then the OpenGroupware packages for OpenSuSE 10.0 will install and run.