Archive

Posts Tagged ‘html’

Special links: phone calls, sms, e-mails, iPhone and Android apps, …

January 15, 2010 57 comments

Everyone knows to include a link into a page, but what I want to discuss today is how you can include some special links.

Phone calls

This is something cool and with the explosion of smart phones with which you can easily browse this is definitely to consider having on the mobile version of your website. Such a link will initiate a call on your mobile to a specified number. But here the things are a little bit more complicated, requiring different links for different phones. You can easily find how to create such a link consulting the WURFL database and looking at the wml_make_phone_call_string property in the wml_ui category.

Basically this is done as follows:

callto:[phone_number]
mainly appropriate for iPhone and Nokia phones
wtai://wp/mc;[phone_number]
mainly appropriate for Android phones
tel:[phone_number]
reported to work on most of the newest devices. If you want to have only one type of URI, use this one.

In the phone number you can use +(plus) sign for international numbers. What’s also interesting to know is that this can even work on a desktop if you have an application like Skype installed. So maybe it’s a good idea to have this on the classic/desktop website too.

Later update from comments. Another interesting phone link will be how to call a teleconferencing phone number. There you call a phone number and then you enter your conference code, usually followed by hash(#). To do this from a link you will need a pause after the phone number and this is done with , (comma), usually entered by a long press on star(*). I tested this on Android and iOS and it works fine, but you usually need two pauses (,) between the phone number and conference code. Same way you can dial an extension line.

Examples

callto:12345678
call 12345678 on iPhone and Nokia
wtai://wp/mc;12345678
call 12345678 on Android
wtai://wp/mc;+123456789
call an international number on Android
tel:12345678
call 12345678 on most of the newer devices
tel:12345678,,100200#
join 100200 conference code on the conference line 12345678 on most of the newer devices
tel:+12345678,,100200#
join 100200 conference code on the international conference line +12345678 on most of the newer devices

SMS

From a web page you can open the SMS sending application on the user phone with a link like below:

sms:<phone_number>[,<phone_number>]*[?body=<message_body>]

The link contains a comma separated list of phone numbers and an optional message body. The phone numbers are specified as in the call links. Detailed information you can find in the URI Scheme for GSM Short Message Service (draft)

Examples

sms:12345678
SMS to 12345678
sms:12345678?body=Hello my friend
SMS “Hello my friend” to 12345678
sms:123456789,+123456789?body=Hello
SMS to multiple phone numbers, including an international one

There is also an URI version for MMS starting with mms:. On some (mobile) browsers (devices) it is also reported to work smsto: and mmsto:, although I would recommend the first version.

iPhone/iPod/iTunes

When developing a website iPhone is definitely to be considered. You can include links to items in the iTunes store, such as movies, music or application. Apple provided for your convenience a web interface to create such links: ITMS Link Maker. Just specify the country, the search keyowrds and what type of iTunes items. You will get a list of items and when you click one you will get the link. You can even get the link for an author. These links will both work on the desktop and iPhone.

Example: Fluid application (free)

Android market

Android is gaining market share as we speak. Nexus One was just released and in my opinion will beat iPhone. As you include links to iTunes, you can include links to applications in Android Market.

market://search?q=<query>

or

market://details?id=<your.package.name>

The query can include keywords or can identify a specific application using q=pname:your.package.name and then the link will be market://search?q=pname:<your.package.name>.

Ovi Store

Nokia created a new fresh application repository for their latest phone – Ovi Store. If you want to include a link to an application, search for it and then copy the link that it will look like http://store.ovi.com/content/XXXXX?clickSource=publisher+channel. Just remove the last part and include http://store.ovi.com/content/21309 into your page, where XXXXX is the application Id. You can also include a link to a publisher’s page containing a summary of their application. The link is found on any of the publisher’s application (see by Publisher Name) and it will look like http://store.ovi.com/publisher/Publisher+Name

Windows Marketplace

We cannot exclude Microsoft from the list with their Windows Phone Marketplace. Same steps to find out the application link: search it, copy the link location and strip the last part. The link will look like http://marketplace.windowsphone.com/details.aspx?appId=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, where xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is the application ID, clearly resembling a GUID. Here publishers don’t have a personal page.

BlackBerry App World

For all those BlackBerry fans, there is BlackBerry App World. Again same process: search for the application and copy the link location of the application icon. The format is http://appworld.blackberry.com/webstore/content/XXXXX, where XXXXX is the application ID. The app authors have a page here with a summary of their apps. See the by Author link under each application. The link will be like http://appworld.blackberry.com/webstore/vendor/XXXX, where XXXX is the author ID.

Geolocation

Nowadays you cannot even imagine a world without maps and GPS. More and more contact pages include a map too. Nowadays smart phones usually include a map application and opening a map with your location in it would be quite nice for the user

geopoint:latitude,longitude

As simple as this and you know where to go.

Messengers

From a web site you can also interact with the messenger applications installed on your machine.

Yahoo Messenger

ymsgr:ACTION?USERNAME&m=YOUR+MESSAGE

The possible actions are addfriend, sendIM and call. The message can, of course, be specified only for sendIM action. The USERNAME should be your.account@yahoo.com or your.account@hotmail.com.

Example: ymsgr:sendIM?beradrian&m=Hello – Say Hello in Yahoo Messenger.

Windows Messenger

msnim:ACTION?contact=USERNAME

The possible actions are chat, add (to add a contact), voice (for voice call) and video (for video call). The USERNAME should be your.account@yahoo.com or your.account@hotmail.com.

Example: msnim:chat?contact=beradrian@yahoo.com – Chat with me in Windows Messenger.

Google Talk

gtalk:ACTION?jid=USERNAME&from_jid=YOURNAME

The possible actions are chat and call (for voice call). The USERNAME and YOURNAME should be your.account@gmail.com. The parameter from_jid is optional and it should be specified only if you use multiple accounts.

Example: gtalk:chat?jid=beradrian@yahoo.com – Chat with me in Google Talk.

Skype

skype:USERNAME?ACTION

The possible actions are chat, add (to add a contact), userinfo (to view a profile) and voicemail (to leave a voicemail). The USERNAME is your Skype ID.

Example: skype:chat?jid=beradrian – Chat with me in Skype.

Lync

Updated on 03/15/2015

sip:USERNAME@DOMAIN

The main thing here is the sip protocol. It is possible that this protocol can be used by other applications too, not being something specific to Lync.

Example: Call John.

WhatsApp

Updated on 06/09/2016

whatsapp://send[/<phone_number>]?text=<message>

Example: Say ‘Hi John’ to number 0123456789 or pick a contact and Say ‘Hello World!’.

There are also other messengers but these are the most widely used. If you need another one, just post a comment.

Mail

It’s pretty easy to include a link for sending an email into your webpage. Basically it’s replacing the http scheme with mailto. So the link will look something like:

mailto:<email>[,<email>]*[?<arguments>]

Such a link will practically open the system application for sending emails (like Outlook or Thunderbird) and the message will be prepopulated with some values. As you can notice you can use multiple email addresses (To) separated by comma.

The possible arguments to be included are:

subject
the message Subject field
cc
the message CC field as a comma separated list of addresses
bcc
the message BCC field as a comma separated list of addresses
body
the message body. If you include a new line in your message you should include %0A.

Examples

mailto:nobody@wordpress.com
the simplest mailto link
mailto:nobody@wordpress.com,no.one@wordpress.com
multiple email addresses
“mailto:nobody@wordpress.com?subject=Testing mailto
specify a subject
“mailto:nobody@wordpress.com?subject=Testing mailto&cc=no.one@wrodpress.com
specify a subject and CC

Just as a side note in the end, it’s better not to rely on this kind of mechanism for handling email on your website. A contact form that sends an email could be a better idea.

Most of these URIs work not only on browsers, but on QR codes readers as well.

Happy linking!!!

Last update: June 9th, 2016.

Categories: Web Tags:

Patu Digua – JavaScript/HTML/CSS Obfuscator/Compressor

September 6, 2009 1 comment

I finally managed to get a first version done for a web obfuscator and compressor.
First of all, why to use such a program. Some may say to hide your HTML/JavaScript/CSS code. Right. This could be one option. And it is powerful enough to do so. But I would personally use it to reduce the size of the code. I tested on a few projects and the code gets reduced up to 60-70% from the initial size. It’s not like a zip but quite good if you take into account that you’re dealing only with scripts.
It is very good practice to comment and indent your code, but this doesn’t have any value at all for the end user, it only eats up his/her bandwidth.
The application has a very nice and intuitive interface (check out the screenshots), it is very customizable and it can be run on both UI and command line mode. A nice feature in the graphical interface is the drop zone, where you can drag and drop files or folders and they are automatically processed. Just switch first to the drop zone mode.
If you want to play with it you can download it from SourceForge or check out its home page.
I would gladly want to hear your opinion or how do you use it.

Categories: Software, Web Tags: , ,

Mobile web

January 10, 2009 3 comments

Mobile web is a new trend and a website for mobile devices is more like a must have these days. It is more likely that your company has a web site, but if you access it with a mobile device, the user experience could be unpleasant.

It is not easy to create a site for mobile devices and it is definitely hard to maintain. And not only because of the huge amount of mobile devices, but also because you have to keep it in sync with the normal one. Following I’ll give you a few pointers.

But first you have to clearly define your mobile web presence. Sometimes it doesn’t even make sense to invest time and effort into it. Let’s say that your solely company product is an FTP server. Definitely you won’t expect to sell it to mobile users. So your entire mobile website can consist of a page stating the company name and logo, product name and description, the link where you can find out more information by browsing with a non-mobile web browser. The best part is that you don’t have to update it and it could remain like this for many years. And that could be the case with many other products for which the target user is an enterprise one, with required access from a non-mobile web browser, like a SDK, online 3D highly graphical game etc.

On the other side of the coin, is when your company product is an exclusively mobile product, like a game for mobile devices, ring tones etc. Then you can simply have only a mobile web site. Of course the desktop users won’t an experience up to their device capabilities, but they aren’t actually your target and your site is not of any real use to them.

And there is the case where your presence has to be strong in both worlds. Following I will concentrate more on this, but most of the below pointers apply to the above cases as well.

  1. CSS. First of all, your web site has to be CSS-based. Forget about tables, use DIVs. Move all CSS rules into external files. Keep the HTML as clean, simple and free of layout settings as possible. Then supporting a mobile device will be as simply as defining a CSS file.
    You can include a CSS in a page and have it active only for mobile devices using the handheld value for the media attribute of the link tag. Even tough this is very convenient, I wouldn’t recommend to be the only thing to rely on. I would define a series of CSS files for each device or set of devices. So, you would include in your HTML the following lines:

    <link rel='stylesheet' type='text/css' href='desktop.css' media='screen'/>
    <link rel='stylesheet' type='text/css' href='[mobile].css' media='handheld'/>
    <link rel='stylesheet' type='text/css' href='print.css' media='print'/>
    

    [mobile] should be dynamically generated and it should point to a file corresponding to the user mobile device. Notice also that I didn’t forget about the printable version :). The CSS media target can be specified also with

    <style type='text/css' href='[mobile].css' media='handheld'>
    </style>
    

    or directly in the CSS

    @media handheld {
        /* mobile specific CSS rules */
    }
    

    If you want to split the devices and optimize for groups, one important criteria could be the screen resolution.

    Even tough this is a very clean approach, as I already said, I would not recommend this to be the only one, especially for very large and complex websites. The mobile website should be a stripped down version, both in terms of layout (most important) and content.

  2. XHTML. Use XHTML instead of HTML. It is better structured and much easier to maintain and to automatically transform.
  3. Dynamically generated content. Even after using CSS for layout, you still have to have different HTML code, then consider generating automatically on the server the specific parts inside the page. For performance purposes you should have in mind using some kind of cache for those automatically generated parts.
    If your entire website is automatically generated, like a portal or an e-commerce website, then you could have different layouts. But don’t fall into having too many device specific code. That should be maintained as well.
  4. Transcoded content. It is the case when you already have a website, specifically a larger one, more likely on the non-mobile web, and you want to reach the mobile users as well. You should consider implementing an automatic translation tool between the two layouts. Of course, here a CSS based website will make your life much more easier. XHTML too.
    As a translation tool, I would recommend XSLT. If your code is HTML, then you have to convert it first to XHTML.
    Don’t forget to resize the images too. Many devices supports images only up to a certain file size, width or height.
    This is a fast and cheap solution, but probably not the best one. Also take into account here the size of your website, otherwise the translation tool could become more expensive then recreating your entire website. And remember that it comes to a cost in performance.
  5. Real life testing. Consider using for testing real mobile devices, not emulators. Use mobile devices with different screen resolution, operating systems, browsers. Don’t forget about touch screens either.
  6. Performance. Test for performance here too, but be careful how you define it. The bandwidth here is different: smaller pages, smaller images, different number of users etc.

If you’re interested in recognizing user’s mobile device on the server side, see my other article: Mobile device recognition.

I hope these will help you in outlining your mobile web personality, but as I said before, first take a step back and think of what exactly you need, want and invest in this.
The mobile web is for sure a different, but thrilling experience.

Categories: Web Tags: , , ,

Fixing IE: CSS fixed position

November 14, 2008 2 comments

I will start a series of articles about how you can fix some IE bugs. We all agree that IE is very buggy, but instead of whining, let’s see what we can do about it. So I will present you the problem, the fix, explain the fix and how you can EASILY INTEGRATE it.

Before, I will explain you a few things that I will use in these fixes. There are few different things in IE when it comes to CSS.

If you prefix a CSS property with _, IE will still recognize it. If you think this can be very useful. You can specify values for CSS properties only for IE. Let’s take an example.

color: green;
_color: red;

The font color will be green in all the browsers, except IE, where it will be red.
Instead of _, you can also use *, + and some other special signs.

The CSS value supports in IE a special value: expression([expr]). The [expr] is a JavaScript expression, which is evaluated and the CSS value is assigned to it. Again an example:

_height: expression((1 + 1) + 'px');

The CSS height in the above example is actually 2 pixels in IE. In the expression we can even use this to refer to the element for which the CSS value is applied.

Now let’s get back to the current issue. If you specify the fixed value for the position property, the element should be absolutely positioned, but relatively to the viewport, instead of the document. For more detailed info, please see the CSS specification. Not surprisingly, this works in most of the browsers, except IE.
And now, the fix. Which is actually very simple. We will use absolute positioning but we will calculate the coordinates dynamically relative to the viewport.
So the CSS code

position: fixed;
top: 10px;
left: 20px;

will have the following IE equivalent

_position: absolute;
_top: expression(((ignoreMe
= document.documentElement.scrollTop
? document.documentElement.scrollTop
: document.body.scrollTop ) + 10) + 'px' );
_left: expression(((ignoreMe
= document.documentElement.scrollLeft
? document.documentElement.scrollLeft
: document.body.scrollLeft ) + 20) + 'px' );

.
Don’t remove the ignoreMe variable as this will force the expression to be evaluated not only the first time the page is loaded, but always.

In the end, a live example. And if you complain that in Mozilla the things are smoother, then simply switch to Mozilla :).

Categories: Web Tags: , , ,

XSLT handler in ASP.net

September 4, 2008 4 comments

Next I will explain you a solution that may come handy to you. First of all, the problem. Quite simple: you have some HTML pages, that you would like to include them in your pages, but in a different format/layout. Unfortunately you cannot modify the pages as you’re not the author. Just to understand better, let’s say that you want to include some Wikipedia articles in your pages. But they have to match with your own layout and you want only some sections of them.
So you have to transform an HTML into another. This sounds pretty much like XSLT and this is what we will use. It will be your task to write the XSLT. I’m only going to tell you how to integrate in your web application.

For the sake of simplicity and reuse, we will write an ASP.net handler for XSLT file that it will take the XSLT file and receive as a parameter the XML/HTML/XHTML URL and it will output the transformed result.

Find below the code for it:

public class XSLTHandler : IHttpHandler
{
    // process the request
    public void ProcessRequest(HttpContext context)
    {
        // the XSLT argument list
        XsltArgumentList xslArg = new XsltArgumentList();

        String url = context.Request.QueryString.Get("u");
        // if no URL, either special or from u parameter then send a NOT_FOUND error
        if (url == null)
        {
            send(context.Response, HttpStatusCode.NotFound);
            return;
        }

        // adding the URL as an XSLT parameter
        xslArg.AddParam("url", "",  url);

        try
        {
            // load the XML document at the specified URL
            XmlDocument xmlDoc = loadXMLDocument(url,
                    "POST".Equals(context.Request.HttpMethod)
                    ? context.Request.Form.ToString() : null);

            // load xsl
            String xslPath = context.Request.MapPath(context.Request.Url.LocalPath);

            // try to get the compiled XSLT from cache
            XslCompiledTransform xslTransform = (XslCompiledTransform)context.Cache.Get(xslPath);
            if (xslTransform == null)
            {
                // if the XSLT file doesn't exist, send a 404
                if (!File.Exists(xslPath))
                {
                    send(context.Response, HttpStatusCode.NotFound);
                    return;
                }

                xslTransform.Load(xslPath);

                // put the XSLT into cache
                context.Cache.Insert(xslPath, xslTransform, new CacheDependency(xslPath));
            }

            // transform
            context.Response.ContentType = "text/html";
            context.Response.Clear();
            xslTransform.Transform(xmlDoc, xslArg, context.Response.Output);

        }
        catch (HttpException exc)
        {
            if (exc.GetHttpCode() == (int) HttpStatusCode.Redirect)
            {
                // if it is to be redirected, redirect to the url
                context.Response.Redirect(url);
            }
            else
            {
                // if any other error, then send the error code
                send(context.Response, (HttpStatusCode)exc.GetHttpCode());
            }
        }
        catch (Exception)
        {
            // if other error send an internal server error response
            send(context.Response, HttpStatusCode.InternalServerError);
        }
    }

    // IHttpHandler method
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

    private void send(HttpResponse Response, HttpStatusCode StatusCode)
    {
        Response.Clear();
        Response.StatusCode = (int)StatusCode;
        Response.StatusDescription = StatusCode.ToString();
        Response.End();
    }

    /// 
    /// Load and returns an XML document from the given url.
    /// 
    /// the url where is the XML content
    /// if not null the request will be a POST request 
    /// and the parameters are sent along with the request; if null then the request method is GET
    /// the loaded XML document
    public static XmlDocument loadXMLDocument(String url, String postParams)
    {
        Object reader;
        if (url.StartsWith("/") || (!url.Contains(Uri.SchemeDelimiter)))
        {
            // if it is a local request then use the internal execute instead of making a web request
            // also the form and query string parameters are preserved
            StringWriter writer = new StringWriter();
            HttpContext.Current.Server.Execute(url, writer, true);
            reader = new StringReader(writer.ToString());
        }
        else
        {
            // create webrequest
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Timeout = RequestTimeout;
            // you can also add a proxy
            //request.Proxy = WebProxy;
            if (postParameters != null)
            {
                // Set values for the request back
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = postParameters.Length;

                // Write the request
                StreamWriter stOut = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
                stOut.Write(postParameters);
                stOut.Close(); 
            }

            // get the response of the request
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            // if something went wrong don't try to parse the document
            if (response.StatusCode != HttpStatusCode.OK)
                throw new HttpException((int)response.StatusCode, response.StatusDescription);

            if (response.ContentType.StartsWith("text/html"))
            {
                // if it is HTML transform it with SgmlReader
                // create instance of SGMLReader and change settings
                SgmlReader sgmlReader = new SgmlReader();
                sgmlReader.WebProxy = Configuration.Proxy;
                sgmlReader.DocType = "HTML";
                sgmlReader.CaseFolding = CaseFolding.ToLower;
                sgmlReader.InputStream = new StreamReader(response.GetResponseStream(), Encoding.UTF8, true);

                reader = sgmlReader;
            }
            else if (response.ContentType.StartsWith("text/xml"))
            {
                // if not html simply get it from the response
                reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8, true);
            }
            else
            {
                // redirect to the normal page, as it is nor HTML nor XML
                throw new HttpException((int)HttpStatusCode.Redirect, url);
            }
        }
        // load the XML document
        XmlDocument xmlDoc = new XmlDocument();
        if (reader is TextReader)
            xmlDoc.Load((TextReader)reader);
        else if (reader is XmlReader)
            xmlDoc.Load((XmlReader)reader);
        return xmlDoc;
    }
}    

To explain shortly what happens: when a file like t.xslt is requested, the XSLTHandler will process the request. First it will load and compile the XSLT file using XSLTCompiledTransform, trying first to load the XSLT compiled object from cache.
Next step is to retrieve the XML/XHTML/HTML content from the URL given as the url parameter. If the content is HTML, then it will be transformed using an SGML parser into XHTML, so it can be transformed with XSLT. Then the actual processing takes place and the result is generated into the response output.

Of course the above code can be extended. You can put in the app configuration if you want to use the cache, what proxy to use, if you want to allow only URLs from some hosts to be parsed and so on. Also other parameters can be added as XSLT arguments: the URL of the XSLT file, the HTTP headers, the request parameters etc.

You saw in the code references to an SgmlReader and I also told you above about feeding the HTML content first into an SGML parser. But how to do it? The SgmlReader is already implemented and you can download it from here and use it like an XmlReader.

Last step is to configure the handler into the Web.config, by simply adding the handler to process *.xsl files:

    <httpHandlers>
        <add verb="*" path="*.xsl" type="XSLTHandler" />
    </httpHandlers>

That’s it!

Categories: Software, Web Tags: , , ,

Web publishing system with Apache and Subversion – part 3

December 3, 2007 1 comment

Authorization


The previous posts were covering setup and authentication. But definitely you would like special rules for different groups and modules in your organization. It is not uncommon that a different group of developers will work on different module(s).

For this you have to use the mod_authz_svn module that comes with the Subversion module and activate it by adding the below line at the beginning of <apache-dir>/conf/extra/wps.conf:


LoadModule authz_svn_module modules/mod_authz_svn.so

Then to configure the access policy you have to add to every <Location> section that defines Subversion repositories:


AuthzSVNAccessFile "/wps/svnaccess.conf"

where /wps/svnaccess.conf is the file holding your access policy.

I will try now to explain the syntax and semantic of this access policy file using a small example:

[groups]
admins = admin1, admin2
web-developers = john, marry
backstage-developers = harry, sally

[/]
* = 
@admins = rw

[web:/]
@web-developers = rw
@backstage-developers = r
editor = rw

[stage:/]
@web-developers = rw
@backstage-developers = rw

You can see that the file is an usual properties files divided in sections, each section beginning with [<section-title>] and ending at the beginning of the next section. The first section defines the groups of users. The users in group are comma separated. It is obvious that john and marry are web developers and there are two administrators (admin1, admin2).

The following sections describes access rules to repositories and directories. The section title has the format repository:path and it specifies a rule for the given path inside the repository. If you don’t specify a repository or a path it will define the rules for all (repositories/paths). Inside these sections every line describing an access rule has the format

username = permissions

or

@groupname = permissions

If the username is *, then it refers to all the users.
The permission can be an empty string for granting no permission, r for reading, w for writing and rw for reading/writing.

Taking into account all this you can see that by default nobody has access to the repositories and administrators have read/write access to everything. Further on, the backstage developers have read access to the website and read/write access to the backstage environment.

More information on these you can find on the SVN book in the section Per-Directory Access Control.

Backstage environment


You already saw that I used the term backstage. This refers to a website with access only for the internal users that it is used for reviewing purposes. Before putting something on your website you may want to be reviewed by certain groups and modified accordingly. Of course we will also have a corresponding Subversion repository as for the main website.

So we will do the same creation of the Subversion repository, create the directory for the web folder, checkout the repository, add the hook and configure Apache. I will only explain here how to write the configuration for Apache, as this is a little bit different because it should be only accessible for internal users. Practically you will add the same authentication configuration as for the Subversion repositories.

<Directory "/wps/backstage">
    AllowOverride None
    Options None
    Order allow,deny
    Allow from all
    
    AuthName "Backstage Authentication"
    Require valid-user
    # for basic authentication
    AuthType basic
    AuthUserFile /wps/passwd
</Directory>

Alias /backstage /wps/backstage
ScriptAlias /backstage/cgi-bin/ 
        "/wps/backstage/cgi-bin/"

#
# Use name-based virtual hosting.
#
NameVirtualHost *:80

<VirtualHost *:80>
    ServerAdmin administrator@domain.com
    DocumentRoot "/wps/backstage"
    ServerName backstage.domain.com
    ServerAlias www.backstage.domain.com
    ErrorLog "logs/backstage.log"
    
    ScriptAlias /cgi-bin/ "/wps/backstage/cgi-bin/"
</VirtualHost>

Conclusions


If we go back to the first post from this series then you can see that we met all the requirements for the desired web publishing system. It is free, OS independent and can be easily installed and setup (a few hours even for the very junior administrators).
The authentication and authorization mechanism can be customized to a very high degree to meet your needs.
Web developers can easily access the Subversion repository using TortoiseSVN. Or even from Dreamweaver (although this extension isn’t free and I haven’t tested it).
If you also install websvn, you will RSS feeds for all the changes made to your website.
And, most importantly, you have all the versioning system advantages brought to your website.

Part 1Part 2

Download configuration files.

Web publishing system with Apache and Subversion – part 2

November 30, 2007 3 comments

If you read the first part of this post, you probably know by now how to install and configure a web publishing system using only Apache and Subversion. But your system will miss one of the most important thing: authentication. So let’s get started and tackle this.

Authentication


We kept all the Apache configuration settings related to Subversion and the website in the file <apache-dir>/conf/extra/wps.conf and further on we will modify this file.
Remember the below section located either in the main server or in a virtual one section?

<Location /svn >

    DAV svn
    SVNParentPath /wps/svnrepo
    SVNListParentPath On

</Location>

We will modify this one to add authentication and authorization.

<Location /svn >

    DAV svn
    SVNParentPath /wps/svnrepo
    SVNListParentPath On

    AuthType basic
    AuthName "SVN repository"
    AuthUserFile /wps/passwd
    Require valid-user

</Location>

The user database will be kept in the plain text file /wps/passwd. To add or modify users you can use the htpasswd utility. So let’s add a developer account:


htpasswd -c /wps/passwd developer

You will be prompted for the password. Later on you can change it with:


htpasswd /wps/passwd developer

.

There are also some other ways to authenticate users, by keeping the users in a database file or using LDAP. You have to specify the authentication provider and use the specific module settings: mod_authn_file, mod_authn_dbm,
mod_authn_dbd,
and mod_authnz_ldap.

Windows authentication


You can also use Windows domain authentication, but this will require just a little bit more work from your side. Anyway this may come in handy in some big organizations, where you don’t want to create special accounts only for this and enable users to use their usual Windows logon credentials.

First of all you have to download the SSPI authentication module and copy it to <apache-dir>/modules. Then add the following line at the beginning of <apache-dir>/conf/extra/wps.conf:

LoadModule sspi_auth_module modules/mod_auth_sspi.so

and the below lines to the Location section corresponding to the SVN repository:

    AuthName "Windows Authentication"
    AuthType SSPI
    SSPIAuth On
    SSPIAuthoritative On
    # set the domain to authorize against
    SSPIDomain your.windows.domain
    # keep domain name in userid string
    SSPIOmitDomain On 
    SSPIUsernameCase lower
    SSPIOfferBasic On 
    # basic authentication shouldn't 
    # have higher priority
    SSPIBasicPreferred Off 

    Require valid-user

Now lets’ discuss in a little bit more in detail the above configuration settings:

  • SSPIAuth – this will turn on/off the Windows authentication module
  • SSPIAuthoritative – this will turn on/off if the the Windows authentication is mandatory or if other modules can be used as a fallback
  • SSPIDomain – the IP address or name of your windows domain controller against which the authentication is run
  • SSPIOmitDomain – if it is On then the domain name is omitted from the user name; so if the user is DOMAIN\user, the user name for Apache and Subversion will actually be user and not DOMAIN\user.
  • SSPIUsernameCase – tells how the user name letter cases are converted. The possible values are lower and upper. If this is not specify then no conversion is made. If you specify lower (recommended) then the user name DOMAIN\User will be transformed to domain\user (if you also specify SSPIOmitDomain On, then the name will become user)
  • SSPIOfferBasic – SSPI by default uses NTLM, a Microsoft proprietary protocol which only IE (and other Windows components/application) understand, so they are able to authenticate you automatically. If you set SSPIOfferBasic On means that it is still authenticating against your Windows domain on the backend, but when it asks the client for a password, it does so using standard HTTP Basic authentication. So if you plan to use other clients to your Subversion repository than IE you must set this on and the client then will prompt you for the domain name and password. This is definately needed if you use TortoiseSVN.
  • SSPIBasicPreferred – if it is On then basic authentication will have higher priority

The authentication possibilities are endless and are depending only on your imagination and needs. I was focusing on these two types as they will probably appear more often: basic in a low or mid-size company and Windows authentication can be smoothly integrated in a big company infrastructure with Windows desktops for the big part of users.

Authorization, setting up a second repository and conclusions will follow soon.

Part 1Part 3

Download configuration files.