Foaf+ssl/HOWTO

From W3C Wiki

How-To Guides for FOAF+SSL

This page is somewhat out of date. Please refer to the The WebID Specification. Here are some more programmer related questions.

For general questions on the protocol see the FAQ


How To Manually Create a WebID-watermarked Certificate for your Pre-existing FOAF File

You already have a FOAF file, and now you want to create the certificate tied to that WebID. In your FOAF file, give your agent a WebID, i.e., a URL that points to you. (So a URL ending in with a #i, #me, #myname, or similar... )

There are a number of methods.

Enter your WebID there, and don't press any of the debug buttons. You can choose the length of time you want your certificate to be valid for.

For a number of other options see the manually creating a WebId thread on the foaf-protocols mailing list]

How To Write Out your Certificate in a Number of Formats

This is now covered in the WebID spec. Many people give themselves a WebID that is the URL of their profile + "#me"; so something like <http://joe.example/profile.rdf#me>. But this ties you closely to the rdf/xml format, and you may later prefer to use the N3 or the RDFa format.

For some good tips, see:

How To Create a WebID-watermarked Certificate in a User Friendly Way

Windows users (soon to include Mac OS X, iOS, and Android users) can use the OpenLink X.509 Certificate Generation Wizard.

Another easy way for users to create certificates is through their web-browsers, through the <keygen> HTML element implemented in most browsers (except Internet Explorer) for years, and standardized in HTML5. IE has an ActiveX equivalent that ships with the Operating System. The keygen element is placed in an HTML form. When submitting the form, the browser calculates a public/private key pair, sends the public key to the server with the other form elements, and stores the private key. When the server returns the certificate, the browser ties the private and public keys together again, and the user is able to make use of the certificate.

The HTML for such a form might look like this --


<form action="profile/keygen" id="keygenform" method="post"> 
    <input id="webId" name="webId" type="hidden" value="https://bblfish.net:8443/user/admin/profile#me"/> 
    <table> 
         <tr> 
	        <td class="formlabel">Certificate Name:</td> 
		<td> 
			  <input alt="create a certificate name that will help you distinguish it from others you may have" 
                              id="cn" name="cn" size="35" type="text" value="admin bblfish-zz@clerezza"/> 
		</td> 
	   </tr> 
	   <tr> 
	         <td class="formlabel">Key strength:</td> 
		 <td id="keystrenghtd"> 
			 <keygen challenge="TheChallenge1" id="spkac" name="spkac"/> 
		</td> 
	    </tr> 
            <tr> 
	          <td class="formlabel">Valid for:</td> 
		  <td> 
			  <input name="days" size="4" type="text" value="365"/> 
			  days <input name="hours" size="4" type="text" value="0.0"/> hours</td> 
             </tr> 
	     <tr> 
		          <td class="formlabel">Comment:</td> 
			  <td><input name="comment" size="80" type="text" value=""/></td> 
	     </tr> 
	     <tr><td class="formlabel"><input id="keygensubmit" type="submit" value="create certificate"/></td><td/></tr> 
	</table> 
</form>

One could devise much simpler forms, leaving the user the need only to click a button.

It is possible then to use some Javascript to convert the DOM into one using Internet Explorer's ActiveX element, as shown in the IEKeygen file from the Clerezza accountcontrolpanel component.

The server can then use the public key to create a certificate. One has to be careful to create a client certificate and not a server certificate, so that the browser will place it in the right keychain.

Below are pointers to how this it is done in a number of languages.

Java based languages

DefaultCertificate.java is part of an OSGi reusable component named ssl.keygen from the Apache Clerezza project. This component is used by the JSR311 Clerezza component of the accountcontrolpanel. The ProfilePanel createcert() method written in the Scala language shows how the server captures the information returned by the keygen form and uses the ssl.keygen classes to create a signed certificate which it then returns.


using OpenSSL

This was discussed a number of times on various threads. See manually creating a WebID for example. ( please distill this information here )

See also the on the Clients page of this wiki

How to WebID-enable your Web 2.0 Application

You have a Web 2.0 application and want to give your users WebIDs. The details will be application specific, but the following steps should give a good idea both of how to proceed, and how relatively easy it is to do this.

Note that the description below uses the Turtle/N3 RDF serialization format (tutorial) as it is easier to write out. But WebID works at the semantic level - there is no requirement for a particular serialization. RDF/XML will do, but so will RDFa or in fact any other serialization format if there is a GRDDL or other transform for it. (It is currently easier to inter-operate with others if the well known RDF formats are used.)

How to Give your Users a WebID

Most Web 2.0 applications have a user profile page and that page should have a stable URL, that the user can send to his friends by email. Often they are something like <http://web2.ex/bob.html>, and in more recent apps they tend to be <http://web2.example/bob>, which make for better OpenIDs.

Use RDFa to markup the HTML template with a few pieces of information. Perhaps the most useful ones will be the equivalent of the following graph

@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix : <#> .

<> a foaf:PersonalProfileDocument;
      foaf:primaryTopic :me .

:me a foaf:Person;
      foaf:nick "bob";
      foaf:depiction </bob/img/beach.jpg> .

Here bob's WebId will end up being <http://web2.example/bob#me> .

In order to make sure your RDFa is good, and says what you want, it is best to make sure it is xhtml. Add the following to the header

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"> 

And you can then test your page using the w3c validator.

To test the rdf generated use both rapper from the Redland raptor library, and the online rdfa distiller until those return the graph that you thought you were encoding. Using different tools helps locate bugs.

When that is done your users can be linked to by other people's foaf files in a distributed social web.

If your profile page is user editable at the script level, then it may be better to generate an rdf/xml representation for the home page using content negotiation.

Give your Users X.509 certificates

In order to allow each of your users to authenticate with that WebId, you need to allow them to create X.509 certificates for their browser using that WebId. To do this you need to

  1. add a data structure to your database associating the user with a number of public keys.
  2. create a form that uses the <keygen> html element so that the browser can create a public/private key pair and send a certificate request to a CGI. An example of such a form can be found on the user pages of webid.myxwiki.org. This script also contains a javascript workaround for Internet Explorer.
  3. Write the CGI to parse the certificate request and create an X.509 certificate. The above form uses the CreateCert CGI which is programmed using this velocity script, and uses some Java classes of which the main entry point is CertificateScriptService.java

[todo: link to other implementations of the same process for other languages]

It should be possible from here for your user once logged in to create any number of differently named certificates. If possible allow them to delete certificates too. At this point they will be able to use any of the Relying Parties.

Allow users to authenticate with foaf+ssl

There are two methods to do this. The first simple one will allow you to get started quickly, and allow you to focus on getting your web application to accept logins via WebIds. The second one will remove your need to rely on any third party server, and speed up the authentication process at the same time. Whatever you do, you will need to find a way to map WebIds to your system's Identifiers.

Map WebIDs to local IDs

In the ideal case your system would be built on an RDF datastore, and you would be able to use blank nodes or URIs to identify your users. Nearly perfect would be if your system allowed you to use URLs as identifiers. But most likely your application will identify people using an internal token such as a number, or perhaps more reliably via an account name ( such as "bob" in the example given above ).

All that is needed to hook into this system, is to create a map from WebIDs to those local identifiers. Some data structure such as

{ <http://bblfish.net/#hjs> <=> "loclid_1",
   <http://romeo.net/#me> <=> "localid_2",
   ...
}

When a user authenticates with a WebID you can then just create an account using whatever programmatic API is made available to do that, and add the map entry from WebID to the new account identifier. Your old system will work just as before, but any WebID conscious code can then use that map to get the WebID and work with that.

Authentication using an external service

To test the above code you don't need to set up an https server yourself. You can use an external authentication service such as foafssl.org. A login button or link on your site need only point to that URL as explained on that page. On authenticating the end user the service will redirect him to a cgi of yours with the users WebId in that parameter list, and a signature to verify the URL has not been tampered with. Writing this piece is as easy as writing parsing a few parameters, and if you want security, testing a signature.

Advanced secure method

If you have arrived here, then you have arrived at the most fiddly bit, but you will now have a good feeling for how useful the service is, and you will see the value in resolving this last piece of the puzzle. Many of the libraries on the main foaf+ssl wiki page are designed to help make this easy. What you need are the following:

  • to open an https port on your server
  • get a certificate from a Certificate Authority (see below for how to get a free one) so that people don't get warning messages when reaching your server
  • alter your https authenticator to not check the CA signature but to use foaf+ssl authentication on certificates using one of the libraries available, or writing your own
  • pass that WebId onto the application somehow


How to create a certificate which includes the WebID URI for multi-purpose use

The following will get you a public key that you can use in your WebID profile, a certificate that you can use to digitally sign your emails as well as to authenticate from your Web browser:

Create a public/private key as you would to SSH to networks:

$ ssh-keygen

Add your URI and email in openssl.cnf, then create the certificate using your private key from above. Import from your email client:

$ openssl req -x509 -new -config openssl.cnf -days 36500 -key id_rsa -out id_rsa.crt

Export to PKCS #12 and import from your browser:

$ openssl pkcs12 -export -in id_rsa.crt -inkey id_rsa -out id_rsa.p12

Copy/paste certificate signature value into your WebID profile:

@prefix cert: <http://www.w3.org/ns/auth/cert#> .

?webid cert:key [ cert:modulus "..."^^xsd:hexBinary; # place the certificate signature value
                  cert:exponent 65537 ] . # replace number with actual value


HOWTO get a cheap certificate for my server?

If you want to turn your server into a foaf+ssl authenticator, and you don't want every browser to show its users and ugly WARNING error message, then you need to add a CA signed certificate to your server. It turns out that StartSSL is giving out free 1 year certificates (see Heise Online article).

For further information see:

Note:

  • Shows up as not having a valid chain of authority in Opera (on what platform?), fine in all other major browsers though.

HOWTO use WebID with PGP/GPG

Both PGP and X509 use the same public key algorithms to do the encryption. Both are certificate formats, with the main difference being that PGP certificates (often misleadingly called keys) can be signed by more than one person, enabling a signature based web of trust. Since WebID is defined at the public key algorithmic layer it can easily work with people using either keys.

Some pointers

HOWTO logout

If you use WebID authentication on an SSL connection to create a cookie for the HTTP layer then you can remove the cookie at the HTTP layer to logout the user. The _https_ endpoint though will not logout the user, and so if the same endpoint is used on subsequent logins either that endpoint will still be using the same TLS session, or the browser will remember to send the same certificate back to that endpoint. It is a bug that browsers do not show the user what identity he is logged in under or that they don't respond correctly to any of the TLS layer exceptions thrown. But in the meantime for Internet Explorer and Firefox the following Javascript on the logout button will enable a logout to work.

function logout(elem) {
   if (document.all == null) {
      if (window.crypto) {
          try{
              window.crypto.logout();
              return false; //firefox ok -- no need to follow the link
          } catch (err) {//Safari, Opera, Chrome
      } else { 
      }
   } else { // MSIE 6+
      document.execCommand('ClearAuthenticationCache');
      return false;
   };
   return true
}

function login(elem)  { logout(elem) }

Then you can just put the following html in your page

<a href={"/user/joe/control-panel"}>Joe</a>|<a href="/logout" onclick="return logout();">logout</a>