[Home] You are not logged in. Login here

Just my stuff

rsa-sha1 signature with openssl


#!/bin/bash

#create keys
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem

#sign and verify
openssl dgst -sha1 -sign private.pem -out "$0".sha1 $0
openssl dgst -sha1 -verify public.pem -signature "$0".sha1 $0

Sessionless Cross Site Request Forgery protection with jQuery

So I found a nice solution to CSRF attack protection within one page js apps. This implementation
- does not require a session on the server
- works transparently on the client: all your $.ajax calls still work the same
- works with cross domain requests (access control happens with cors)
At the protocol level it works like this:

Request

GET /resource HTTP/1.1
Host: example.com
Response
HTTP/1.1 403 Forbidden
X-CSRF-Token: CBhcq4n5k9eHjKvFC0TGlSRr1Ss=-Vo3B+tXH+fw=
At this point the jQuery ajaxPrefilter below reads the X-CSRF-Token header and inserts it in all subsequent requests:
GET /resource HTTP/1.1
Host: example.com
X-CSRF-Token: CBhcq4n5k9eHjKvFC0TGlSRr1Ss=-Vo3B+tXH+fw=
and the server responds with
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
Vary: User-Agent,Accept-Encoding
Content-Length: 30

{"someresource": "somevalue"}

The token can be generated with

hmac-sha1(base64(current date and time without minutes + current user id + some random bytes)-base64(some random bytes))

This way the only thing you need to know on the server is something about the current user that stays constant between requests from the same user. This can be the username, the user id or the email.

On the server, to check the received token just
1. extract the part after the – from the received token
2. generate a token with the function above, but instead of using “some random bytes” use the bytes you extracted in step 1.
3. check if the token received from the client and the generated token are the same. If they match return your response. If not, return 403 Forbidden.

Yay! Sessionless CSRF protection!

//handles csrf tokens

(function() {
    var CSRFHeader = 'X-CSRF-Token';

    //fix firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=608735
    //http://bugs.jquery.com/ticket/10338

    (function ($) {
      var _super = $.ajaxSettings.xhr;
      $.ajaxSetup({
        xhr: function() {
          var xhr = _super();
          var getAllResponseHeaders = xhr.getAllResponseHeaders;
          xhr.getAllResponseHeaders = function() {
              var allHeaders = getAllResponseHeaders.call(xhr);
            if (allHeaders) {
                return allHeaders;
            }
            allHeaders = "";
            var concatHeader = function(i, header_name) {
                if (xhr.getResponseHeader(header_name)) {
                allHeaders += header_name + ": " + xhr.getResponseHeader( header_name ) + "\n";
              }
            };
            // simple headers (fixed set)
            $(["Cache-Control", "Content-Language", "Content-Type", "Expires", "Last-Modified", "Pragma"]).each(concatHeader);
            // non-simple headers (add more as required)
            $(["Location", CSRFHeader]).each(concatHeader);        
            return allHeaders;
          };
          return xhr;
        }
      });

    })(jQuery);

    //utility function
    var getDomain = function(url) {
        var m = url.match(/://(.[^/]+)/);
        if (m == null || m.length < 2) {
            m = (document.location.href + url).match(/:\/\/(.[^/]+)/);
        }
        return m[1];
    };

    var getCSRFTokenForDomain = function(domain) {
        return window.csrfToken && window.csrfToken[domain];
    };

    var saveCSRFTokenFromXHR = function(jqXHR, domain) {
        if (!window.csrfToken) {
            window.csrfToken = {};
        }

        var currentCsrf = jqXHR.getResponseHeader(CSRFHeader);
        if (currentCsrf) {
            window.csrfToken[domain] = currentCsrf;
        };
    };

    $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
        var csrfToken = getCSRFTokenForDomain(getDomain(options.url));

        if (csrfToken) {
            jqXHR.setRequestHeader(CSRFHeader, csrfToken);
        }

        // Don't infinitely recurse
        originalOptions._retry = isNaN(originalOptions._retry)
            ? 3 //max retries
            : originalOptions._retry - 1;

        // save the original error callback for later
        if (originalOptions.error)
            originalOptions._error = originalOptions.error;

        // overwrite *current request* error callback
        options.error = $.noop();

        // setup our own deferred object to also support promises that are only invoked
        // once all of the retry attempts have been exhausted
        var dfd = $.Deferred();
        jqXHR.done(function(args) {
            //check if there is a csrf token in the response.
            saveCSRFTokenFromXHR(jqXHR, getDomain(originalOptions.url));

            dfd.resolve(args);
        });

        // if the request fails, do something else yet still resolve
        jqXHR.fail(function (jqXHR, textStatus, errorThrown) {
            var args = Array.prototype.slice.call(arguments);

            if (jqXHR.status === 403 && originalOptions._retry > 0) {
                saveCSRFTokenFromXHR(jqXHR, getDomain(originalOptions.url));

                var newHeader = {};
                newHeader[CSRFHeader] = getCSRFTokenForDomain(getDomain(originalOptions.url));
                originalOptions.headers || (originalOptions.headers = {});
                $.extend(originalOptions.headers, newHeader);

                // retry with our modified options
                $.ajax(originalOptions).then(dfd.resolve, dfd.reject);
            } else {
                // add our _error callback to our promise object
                if (originalOptions._error)
                    dfd.fail(originalOptions._error);
                dfd.rejectWith(jqXHR, args);
            };
        });

        // now override the jqXHR's promise functions with our deferred
        return dfd.promise(jqXHR);
    });
})();

Mobile HTML Frameworks that work with PhoneGap

We are in the process of building a new mobile app. We are a bunch of pretty talented js devs, so after looking around a bit jQuery Mobile and PhoneGap seemed the right path to take for us. We already use a JavascriptMVC framework for our Webapps, so we wanted to reuse that. JavascriptMVC is very similar to backbone.js, so if you use that you are probably in the same boat as we are.

jQuery Mobile

We spend about one week making the server side json api and the jQM pages. Christophe has a very nice writeup about how to use jQM with backbone.js, and his hints worked great for us. We tested the app in the browser (ff and Chrome) while building it, and everything looked awesome. Then our test devices got in and we compiled the HTML/JS app to a hybrid app, installed it on an android 2.x device and to our surprise there where no transitions. Well, jQM is used by a lot of people we thought, so there must be someone out there who fixed this? After looking around a bit we found out that:
- jQM does not support transitions on 2.x devices and they basically gave up on them.
- a very cool guy implemented a jQM wrapper for iscroll4 (a very nice scrolling library), but after testing it we found out that it locked up sometimes on the devices and it was a bit awkward to use (this is my subjective opinion).


So, to the point: jQM in PoheneGap/as a hybrid app does not work on Android 2.x devices. We tested it briefly on a 4.x device as well. It didn’t work there too.
We gave up on jQM. It doesn’t work for us. Friends don’t let friend use jQM.

Kendo UI Mobile

The json api for our app was done. We just needed a nice frontend for it. And since jQM didn’t work we looked for something else. Back to google we found Kendo UI Mobile. It looked awesome on the demo page, but has a fee attached to it (not much really: $199). We are ok with that, as long as we get the source with it so we can debug it in case something goes wrong. And that is included in the price (they say so).
So we tried that out too. We compiled all the examples in PG and tried them out. It worked great on our test devices. All transitions worked, the Widgets looked very nice and reflect the look and feel of the device they are running on.
The only problem we had, and could not fix, was that it interfered with our routing mechanism, about the same problem this guy had. I think somehow we can workaround this problem, we still have to try a bit harder. What makes me feel a bit bad about Kendo is the fact that not many people seem to use it, and so if we have a problem we may not find a solution to it right away in the forums or on some blog, but we have to dig deep by ourselves and/or contact Kendo technical support. Kendo is at this time an open question.


+ it looks and feels very nice, is fast and reflects the look and feel of the os it runs on
+ easy to use if you use the Kendo way of doing it.


- not many people seem to use it
- difficult to use if you want to just have the nice widgets with your own framework like backbone.js/javascriptMVC


Sencha Touch

In a world of hurt if you want to use it with your own js fw. To slow to startup. We don’t want that. Next.

jqMobi/jqUi

jqUi was a nice surprise. We downloaded the kitchensink app and compiled it with PG. Transitions worked great and the look of the widgets is really nice. But it hasn’t the native look and feel widgets like Kendo, but that’s ok with us: you can give your users a great experience even if the look and feel of the app is different.
So we started to use it with JavascriptMVC and found some problems with the routing, as others have too, but the solution was there on the forum.


+ it looks and feels very nice, is fast
+ easy to use on it’s own or with your own js fw.


- not many people seem to use it
- does not reflect the look and feel of the os it runs on


Conclusions

If you are an experienced javascript dev and want to go mobile with hybrid apps, you have to make some tradeoffs. What you choose depends on
- how good you want your app to be
- how much $$$/time you want to invest in the app
If you have the time and money to invest, go native for the best user experience.
If you are cheap like us, but want to give your users a good experience anyway, Kendo UI Mobie or jqUi is the best choice at the moment.

Destroy/remove/hide/kill the show desktop button in Windows 7

I actually hate that button. I am used to go to the lower-right corner with my mouse when I want to see the calendar, not when I want to see my desktop. That’s why I wanted to get rid of it, but there is no option anywhere to do so.
Long story short, I wrote a very small C++ program to kill it. Here it is:
  
// DestroyShowDesktop.cpp : Kill the show desktop button, by S2
//

#include "stdafx.h" 
#include "windows.h" 

int _tmain(int argc, _TCHAR* argv[])
{

    HWND hTrayWnd, hTrayNotifyWnd, hButton;

    hTrayWnd = FindWindow(_T("Shell_TrayWnd"), _T(""));
    if (!hTrayWnd) return 0;
    hTrayNotifyWnd = FindWindowEx(hTrayWnd, 0, _T("TrayNotifyWnd"), _T(""));
    if (!hTrayNotifyWnd) return 0;

    //Get the Show Desktop Button which is a child of TrayNotifyWnd.
    hButton = FindWindowEx(hTrayNotifyWnd, 0, _T("TrayShowDesktopButtonWClass"), _T(""));
    if (!hButton) return 0;

    //KILL IT!
    SendMessage(hButton, WM_DESTROY, NULL, NULL);

    //repaint the systray
    SendMessage(hTrayNotifyWnd, WM_PAINT, NULL, NULL);

    return 0;
}


And if you don’t want to compile it yourself, here is the compiled exe.
Just move a link to it in your Startup Start menu, set it to run with Admin rights and you are all set.

Generating a UsernameToken with WSS4J

Generate a Web Service Security UsernameToken header (if you want to manually do the stuff your middleware should take care of):
  
import java.io.ByteArrayInputStream;
import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;

import org.apache.axiom.om.util.StAXUtils;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder;
import org.apache.rampart.util.Axis2Util;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.message.WSSecHeader;
import org.apache.ws.security.message.WSSecTimestamp;
import org.apache.ws.security.message.WSSecUsernameToken;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

public class CreateToken {

    /**
     * @param args
     * @throws ParserConfigurationException 
     * @throws IOException 
     * @throws SAXException 
     * @throws WSSecurityException 
     * @throws XMLStreamException 
     */
    public static void main(String[] args) throws WSSecurityException, SAXException, IOException, ParserConfigurationException, XMLStreamException {
        String username = "ciccio";
        String password = "panza";

        Document doc = Axis2Util.getDocumentFromSOAPEnvelope(getSoapExEnv(), false);        

        WSSecHeader secHeader = new WSSecHeader();
        secHeader.insertSecurityHeader(doc);

        WSSecUsernameToken utBuilder = new WSSecUsernameToken();
        //utBuilder.setPasswordType(WSConstants.PASSWORD_TEXT);
        utBuilder.setUserInfo(username, password);
        utBuilder.build(doc, secHeader);

        WSSecTimestamp tsBuilder = new WSSecTimestamp();
        tsBuilder.build(doc, secHeader);
        System.out.println(org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc));

        //System.out.println(Axis2Util.getSOAPEnvelopeFromDOMDocument(doc, false).toString());
    }

    private static SOAPEnvelope getSoapExEnv() throws SAXException, IOException, ParserConfigurationException, XMLStreamException {
        String d = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                "   <soapenv:Header/>" +
                "   <soapenv:Body>" +
                "      <Send>" +
                "         <mailbox>" +
                "            <mailBox>?</mailBox>" +
                "            <userId>?</userId>" +
                "            <password>?</password>" +
                "         </mailbox>" +
                "      </Send>" +
                "   </soapenv:Body>" +
                "</soapenv:Envelope>";

        return (SOAPEnvelope)new StAXSOAPModelBuilder(StAXUtils.createXMLStreamReader(
                new ByteArrayInputStream(d.getBytes())), SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI)
                .getDocumentElement();

    }

}

working

on http://31337.it/

Benchmark the load time of a page with Javascript

Sometimes the bottleneck is not the Database or the Application itself, but something between the client and the app. So it can be useful to track the load time with js on the client directly. This script measures the load time and then sends it back to the server with an AJAX GET request, so the server can save it somewhere.
<script Language="JavaScript">
var from_time = new Date();
from_time = from_time.getTime();

function benchmark_loading_time()
{
  var to_time = new Date();
  to_time = to_time.getTime();
  var msecs = (to_time - from_time);

  //submit the result
  var req = null;
  try { req = new XMLHttpRequest(); } catch(e) {}
  if (!req) try { req = new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) {}
  if (!req) try { req = new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) {}
  req.open("GET", '/benchmark_loading_time/?msecs=' + msecs + '&url=' + location.href, false);
  req.send(null);
}
</script>

<body onLoad="benchmark_loading_time()">

Oracle concat function

If you need to concatenate varchars:
CREATE OR REPLACE FUNCTION Fnc_Concat_List (cur SYS_REFCURSOR, separator VARCHAR2) RETURN VARCHAR2 IS
    ret VARCHAR2(32000);
    tmp VARCHAR2(4000);
BEGIN
    LOOP
    FETCH cur INTO tmp;
        EXIT WHEN cur%NOTFOUND;
        ret := ret || separator || tmp;
    END LOOP;

    ret := SUBSTR(ret, LENGTH(separator) + 1);
    RETURN ret;
END;
/

Example:
CREATE TABLE hallo (ID number(10) PRIMARY KEY, NAME varchar2(255));
INSERT INTO hallo (ID, NAME) VALUES (1, 'a');
INSERT INTO hallo (ID, NAME) VALUES (2, 'b');
INSERT INTO hallo (ID, NAME) VALUES (3, 'c');
COMMIT;

SELECT fnc_concat_list(CURSOR(SELECT name from hallo), ', ') from dual;

Oracle pipelined function

  
CREATE TABLE hallo (ID number(10) PRIMARY KEY, NAME varchar2(255));
INSERT INTO hallo (ID, NAME) VALUES (1, 'a');
INSERT INTO hallo (ID, NAME) VALUES (2, 'b');
INSERT INTO hallo (ID, NAME) VALUES (3, 'c');
COMMIT;

CREATE OR REPLACE PACKAGE hoi IS
    TYPE hallo_lines IS TABLE OF hallo%ROWTYPE;
    FUNCTION h RETURN hallo_lines pipelined;
END;

CREATE OR REPLACE PACKAGE BODY hoi IS

    FUNCTION h RETURN hallo_lines pipelined IS
        r_hallo         hallo%ROWTYPE;
    BEGIN

        FOR i IN (SELECT ID, NAME FROM hallo)
        LOOP
            r_hallo := i;
            -- r_hallo.ID := i.ID;
            -- r_hallo.NAME := i.NAME;

            PIPE ROW(r_hallo);
        END LOOP;
    END;
END;

select * from table(hoi.h);

JBoss and SPNEGO authentication with GSS-API

This took about a million google searches to get done, so here is a blog post to explain the steps that need to be done to get a Java application deployed on JBoss to use GSS-API to authenticate the user making the request.

Prerequisites


  • A working KDC (Active Directory or something equivalent)
  • JBoss (I used 5.0.1.GA)
  • a keytab file

Configure JBoss


On a clean JBoss installation, open server/default/conf/login-config.xml and add the following at the end (just before </policy>):
    <application-policy name="com.sun.security.jgss.accept">
        <authentication>
            <login-module code="com.sun.security.auth.module.Krb5LoginModule" flag="required">
                <module-option name="debug">true</module-option>
                <module-option name="principal">HTTP/principal@REALM</module-option>
                <module-option name="storeKey">true</module-option>
                <module-option name="useKeyTab">true</module-option>
                <module-option name="doNotPrompt">true</module-option>
                <module-option name="keyTab">/path/to/keytabfile.keytab</module-option>
            </login-module>
        </authentication>
    </application-policy> 

and comment the whole <application-policy name="Others"> section right above.
Now we need to add some global VM parameters to Java: open /bin/run.conf and add
JAVA_OPTS="$JAVA_OPTS -Djavax.security.auth.useSubjectCredsOnly=false" 
JAVA_OPTS="$JAVA_OPTS -Djava.security.krb5.conf=/path/to/krb.conf" 

/path/to/krb.conf looks like this
[libdefaults]
    default_realm = YOURREALM
[realms]
 YOURREALM = {
  kdc = your.kdc
 }

and is the global Kerberos config file for your apps.
You should also increase the maximum HTTP header size permitted by the embedded Tomcat installation, since with Single-Sign-On HTTP headers may exceed the default of 4kb in complex Active Directory environments. Add a property maxHttpHeaderSize="32768" to your HTTP connector configuration in server/default/deploy/jboss-web.deployer. If your HTTP headers become larger than this setting, Tomcat just discards the requests without any log output, which can cause a lot of trouble.
Well, almost done. Now you are free to get the SPNEGO token from inside your app and do with it whatever you want (for ex. delegate the credentials to call some other service).