[Home] You are not logged in. You can create an account here or login here

Just my stuff

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).

SPNEGO authentication and credential delegation with Java

Almost all our Web Services are secured with SPNEGO. This way we can forward the identity of the user calling a service to another service, or/and through the tiers of the service. If, for example, a user calls the “check my mail” WS, the service can get the identity of the user from the SPNEGO token, request a new kerberos token from the KDC for that user, and use that token to check for new mail on the IMAP server on behalf of the user.
Client[1] ---> WS[2] ---> more services[3]

Client calls WS, authenticates with his kerberos token, and WS can use that token to authenticate to more services on behalf of the Client.
I had to search the Web for a few hours to find out how SPNEGO and delegation works with Java, so here is a summary:
  1. The client sends a request to the server
  2. The server answers with
    Status: 401 - Authorization Required
    WWW-Authenticate: Negotiate
    
  3. The client receives the 401 and sends the SPNEGO token to the server:
    Authorization=Negotiate YIIGHwYGKwYBBQUCoIIGE[...]
    
  4. The server then has to decode and validate that token. If the token is forwardable then the server can use it to request a new token to authenticate to other services.

This is how to decode a SPNEGO token in Java:
byte[] token = null;
byte[] tokenForPeer = null;
byte[] tokenForEndpoint = new byte[0];

String endpointSPN = null;

GSSManager manager = GSSManager.getInstance();

GSSContext context = null;

GSSCredential clientCred = null;
GSSCredential myCred = null;

try {
  //Oid krb5MechOid = new Oid("1.2.840.113554.1.2.2");
  Oid spnegoMechOid = new Oid("1.3.6.1.5.5.2"); 

  //first obtain it's own credentials...
  myCred = manager.createCredential(null, GSSCredential.DEFAULT_LIFETIME, spnegoMechOid, GSSCredential.ACCEPT_ONLY);
  //...and create a context for this credentials...
  context = manager.createContext(myCred);

  //...then use that context to authenticate the calling peer by reading his
  //spnego token
  System.out.println(authorization);
  token = Base64.decode(authorization);
  tokenForPeer = context.acceptSecContext(token, 0, token.length);

  if (!context.isEstablished()) return false;
  if (tokenForPeer != null) {
    System.out.println("there is a token to send back to the peer, but I leave this out for now");
  }

  System.out.println("Context Established! ");
  System.out.println("Client principal is " + context.getSrcName());
  System.out.println("Server principal is " + context.getTargName());

} catch (WSSecurityException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
} catch (GSSException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}

the authorization String contains the SPNEGO token from the request. Once we have established the context, we can check if the credentials can be delegated, and then request the new token:
//check if the credentials can be delegated
if (!context.getCredDelegState()) {
  System.out.println("credentials can not be delegated!");
  return false;
}

//get the delegated credentials from the calling peer...
clientCred = context.getDelegCred();

//now create the spnego token to send to the endpoint:
//create target server SPN
endpointSPN = "HTTP/spnegotestserver.domain.com@REALM.COM";
System.out.println("Endpoint: " + endpointSPN);
GSSName gssServerName = manager.createName(endpointSPN, GSSName.NT_USER_NAME);

//...and create a new context pretending to be the caller
clientContext = manager.createContext(gssServerName.canonicalize(spnegoMechOid), spnegoMechOid, clientCred, GSSContext.DEFAULT_LIFETIME);

//this should be an option: enable GSS credential delegation
clientContext.requestCredDeleg(true);
// create a SPNEGO token for the target server
tokenForEndpoint = clientContext.initSecContext(tokenForEndpoint, 0, tokenForEndpoint.length);

Done. Now we have a new tokenForEndpoint object that contains a valid SPNEGO token with the delegated credentials from the calling user. Insert it in the headers for the HTTP request to the next service in the chain like this
"Negotiate " + Base64.encode(tokenForEndpoint)

and you are good to go.

Automating svn delete and svn add

Patrick asked me on Friday if I could somehow make
svn move file
svn delete file
and
svn add file
somehow transparent to his not-so-computer-savy secretary. He is using svn to centrally store documents and files other people in his company edit and create, so the people can comment on changes, and work on the files while offline.
We thought a bit about it, and this is what came out:

#!/bin/bash
#this depends on inotify-tools
#folder to watch
FOLDER=~/tmp/svn_test/repo
###############################

inotifywait -m --format '%e %w %f' -r $FOLDER -e move -e create -e delete --exclude .svn 2>/dev/null|
while read EVENT
do
  EV=`echo $EVENT|cut -d' ' -f1|cut -d',' -f1`
  FOLDER=`echo $EVENT|cut -d' ' -f2`
  FILE=`echo $EVENT|cut -d' ' -f3`
  echo event $EVENT
  #continue
  if [ "$EV" == "CREATE" ] || [ "$EV" == "MOVED_TO" ]; then
    svn add --force "$FOLDER/$FILE" 
  elif [ "$EV" == "DELETE" ] || [ "$EV" == "MOVED_FROM" ]; then
    svn delete "$FOLDER/$FILE" 
  fi
done

This way, if Ms. Secretary works on files on her working copy of the svn repository, and this script is running, for every file creation, move or delete the corresponding svn command is executed.
This of course works while offline too, so when Ms. Secretary is back in the office, she can just execute the svn update && svn commit command and everything is back in sync.

Consume SSL protected Web Services with soap4r

After hours of google this deserves a blog post. I did not find a clear example about this, so I am writing one.
I had the need to call a .NET Web Service over https with mutual authentication and basic authentication.
First of all I installed the soap4r gem, then the httpclient gem (because that one supports basic authentication).
Then I made a folder called “certs” with all the certificates and key files I had:
- ca.cer – the certificate of the certification authority that signed the server certificate
- server.cer – the certificate of the server (signed by the guys who own ca.cer)
- client.cer – the client certificate I need to send along the request to get the content
- client.key – the key file for the client certificate
That’s all the certs and key files I needed.
Now it was time to try to get the wsdl:
require 'http-access2'

url = 'https://secure.example.com/web_service/wsdl'

client = HTTPAccess2::Client.new()
client.ssl_config.set_client_cert_file('certs/client.cer', 'certs/client.key')
client.ssl_config.set_trust_ca('certs/ca.cer')
client.set_basic_auth(url, 'username', 'password')
puts client.get(url).content

This worked.
Time to try soap4r:
require 'rubygems'  #if you installed httpclient with rubygems you need this
require 'soap/wsdlDriver'

#this validates the server certificate
#so you can be sure that the server you are
#sending data to is the server you have the
#certificate of in certs/server.cer
def validate_certificate(is_ok, ctx)
  cert = ctx.current_cert
  unless (cert.subject.to_s == cert.issuer.to_s) #check the server certificate only
    is_ok &&= File.open('certs/server.cer').read == ctx.current_cert.to_pem
  end
  is_ok
end 

wsdl = 'https://secure.example.com/web_service/wsdl'
driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
#driver.wiredump_dev = STDOUT

driver.options['protocol.http.ssl_config.verify_callback'] = method(:validate_certificate)

results = driver.web_service_method(arg1, arg2)
p results

To tell soap4r that you want basic authentication and where the certificate files are, you need to create a soap/property file with the following content:
client.protocol.http.basic_auth.1.url = https://secure.example.com/web_service/wsdl
client.protocol.http.basic_auth.1.userid = username
client.protocol.http.basic_auth.1.password = password

client.protocol.http.ssl_config.client_cert = certs/client.cer
client.protocol.http.ssl_config.client_key = certs/client.key
client.protocol.http.ssl_config.ca_file = certs/ca.cer
client.protocol.http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER
client.protocol.http.ssl_config.ciphers = ALL
client.protocol.http.ssl_config.verify_depth = 1

This file is loaded at startup (you can find other options in soap/lib/soap/httpconfigloader.rb), and configures the ssl and basic auth stuff for soap4r.