Saturday, December 31, 2011

Sign SOAP messages with suds

What's the Signature
Signature in SOAP message is part of WS-Security.
You can read the specification here:
http://schemas.xmlsoap.org/specs/ws-security/ws-security.htm#ws-security__toc6201557

And here is a capture of a SOAP message with signature.


How to sign the SOAP messages:
Fortunately, a guy named András Veres-Szentkirályi from Europe, post the solution in "suds mailing list"
http://lists.fedoraproject.org/pipermail/suds/2011-December/001606.html

and, he put the detail in his master thesis:
http://vsza.hu/thesis-beta.pdf

Code is here, work as a plugin in suds:
https://github.com/dnet/SudsSigner


Install dependence:
apt-get update
apt-get install gcc python-dev python-lxml python-libxml2 libxml2-dev libxmlsec1-dev python-suds python-openssl
git clone https://github.com/dnet/pyxmlsec.git
cd pyxmlsec
python ./setup.py build (select openssl as crypto engines)
sudo python ./setup.py install



Addition:
I met an Error in <plugin.py>,line 56, it seems no method "get_signature_algorithm()" in "cert" object which is actually a "X509" (http://packages.python.org/pyOpenSSL/openssl-x509.html) instance.

The OpenSSL document is based on version 0.13, while I'm using version 0.10 which without this method.

Well, it's not a big problem, since I know the exactly signature_algorithm my certification using, I just hard code the line 56 as:
algo = "rsa", #self.cert.get_signature_algorithm()


--------------
OK, now your code should looks like:
signer = SignerPlugin(r"/xxxx.pem")
c = Client(url, transport = ssltrans, prettyxml=True, plugins=[signer])

over.

Wednesday, December 28, 2011

Enable SSL for you website over Apache

run commands underline with root permission , or add prefix sudo.
tested on Ubuntu 11.04


1,install openSSL
in most conditions, openSSL was already installed.
however, run command to make sure it was installed
apt-get install openssl


1.5,enable SSL module
a2enmod ssl


2,edit /etc/apache2/ports.conf
add following, if they were not existing. You can leave them in <IfModule mod_ssl.c>, that's fine, coz you've enabled SSL module

NameVirtualHost *:443
Listen 443



3,create self-signed certification
mkdir /etc/apache2/ssl
openssl req -new -x509 -nodes -out  /etc/apache2/ssl/apache.pem -keyout  /etc/apache2/ssl/apache.key


4,edit /etc/apache2/sites-available/default-ssl
Step1,edit <VirtualHost __default__:443> to <VirtualHost *:443>
Step2,make sure "SSLEngine on" is uncommented.
Step3,modify file path of certificate file and key file.

      SSLCertificateFile    /etc/apache2/ssl/apache.pem
      SSLCertificateKeyFile /etc/apache2/ssl/apache.key




5,firewall setting
if you have a firewall running. make sure port 443 for SSL, is not forbidden.
ufw allow 443


6,restart apache2
service apache2 restart


More:
7,Error apache2 Error code: ssl_error_rx_record_too_long

sudo a2ensite default-ssl
sudo /etc/init.d/apache2 reload


Sunday, December 18, 2011

squid in Ubuntu 11.04

1, It should be easy
I installed squid from "Ubuntu software center".

then modified the "squid.conf" under /etc/squid/conf
follow steps from Ubuntu help:
https://help.ubuntu.com/8.04/serverguide/C/squid.html

then I tried to start squid by "/etc/init.d/squid restart"
it always response as "Rather than invoking init scripts through /etc/init.d, use the service(8) utility, e.g. service squid restart ..."

OK. I run command
service squid restart

OMG, "Unknown instance", faint....
what the hell.


2, calm down
Google this issue. It seems as a common problem.


3, Okay, let's fix it....
Go to squid official website , download the latest stable code, current is 3.1.18
http://www.squid-cache.org/Versions/v3/3.1/

follow instructions in INSTALL.
config it, build it , and install it by root.

edit the "squid.conf" , add "http_access allow all" at the beginning of the http_access control block (before other http_access). It makes the proxy can access by others.

next , initialize the cache, and start the proxy with root.
sudo /usr/local/squid/sbin/squid


4,everything should be fine. 
you can find the proxy listen on the port (default is 3128) by run command "netstat |grep 3128"
Also, don't forget to verify it by another computer.



Thursday, December 15, 2011

Calling log & SMS monitor (Android)


1, Monitor incoming calls




1: class DiagPhoneStateListener extends PhoneStateListener
   2: {        
   6:     @Override
   7:     public void onCallStateChanged(int state, String incomingNumber)
   8:     {        
   9:         switch(state)
  10:         {
  11:             case TelephonyManager.CALL_STATE_IDLE: //phone status goes to idle
  12:                 Logger.d(TAG, "phone call state -> idle");
  13:                 m_bIncomingFlag = false;   
  14:                 break;
  15:             case TelephonyManager.CALL_STATE_RINGING: 
  16:                 m_bIncomingFlag = true;                                                
  17:                 Logger.d(TAG, "incoming call ringing, " + incomingNumber);
  18:                 break;
  19:             case TelephonyManager.CALL_STATE_OFFHOOK: 
  20:                 if (m_bIncomingFlag) //if coming call
  21:                 {                        
  22:                     m_startTime = new Date();
  23:                     Logger.d(TAG, "incoming accept");
  24:                 }
  25:                 break;
  26:         }
  27:     }
  28:   }
  29:  
  30: TelephonyManager m_telMan = (TelephonyManager)m_context.getSystemService(Context.TELEPHONY_SERVICE);
  31: m_telMan.listen(m_diagCallingReceiver, PhoneStateListener.LISTEN_CALL_STATE | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);

additional permission


   1: <uses-permission android:name="android.permission.READ_PHONE_STATE" />
   2: <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /



2, Monitor outgoing calls


   1: class OutCallReceiver extends BroadcastReceiver 
   2: {    
   3:     public void onReceive(Context context, Intent intent) 
   4:     {
   5:         String action = intent.getAction();
   6:         if (action.equals(Intent.ACTION_NEW_OUTGOING_CALL)) //call others
   7:         {
   8:             //an outgoing call
   9:         }
  10:     }
  11: }
  12: IntentFilter filter = new IntentFilter();
  13: filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 
  14: filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);                
  15: m_context.registerReceiver(m_ocReceiver, filter);

[Important]

on some devices, manufactures use their own Calling App instead of the standard Google one. Their own calling app might not broadcast “Intent.ACTION_NEW_OUTGOING_CALL”, so you might can not catch the outgoing call intent.

e.g. You can catch the intent on Nexus One, Nexus S, while the receiver not working on HTC My Touch.



3, Monitor incoming SMS


   1: class SMSReceiver extends BroadcastReceiver 
   2: {    
   3:     public void onReceive(Context context, Intent intent) 
   4:     {
   5:         String action = intent.getAction();
   6:         Logger.e(TAG, "coming action: " + action);
   7:         
   8:         if (action.equals(ACTION_SMS_RECEIVED))
   9:         {
  10:             Bundle extras = intent.getExtras();
  11:             if (extras == null)9
  12:                 return;                
  13:             
  14:             Object messages[] = (Object[]) extras.get("pdus");
  15:             SmsMessage smsMessage[] = new SmsMessage[messages.length];
  16:             for (int n = 0; n < messages.length; n++) 
  17:             {
  18:                 smsMessage[n] = SmsMessage.createFromPdu((byte[]) messages[n]);
  19:                 
  20:                 String msgBody = smsMessage[n].getMessageBody();
  21:                 String msgAddress = smsMessage[n].getOriginatingAddress();
  22:                 String msgTime = String.valueOf(smsMessage[n].getTimestampMillis());
  23:             }                          
  24:         }                
  25:     }
  26: }
  27:  
  28: IntentFilter filter = new IntentFilter();
  29: filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
  30: filter.addAction(ACTION_SMS_RECEIVED);    
  31: m_context.registerReceiver(m_smsRec, filter);

additional permission


   1: <uses-permission android:name="android.permission.RECEIVE_SMS" />

4, Monitor outgoing SMS

Sorry, I didn’t find a similar solution like monitor incoming SMS. But I have another solution descripting below.

---------------------------------



5, Simplest solution

OK, here comes the simplest solution!

Monitor both incoming/outgoing calls and SMS by ContentObserver

[Important]

When observing to SMS, you should call moveToLast() to get the latest SMS event.

But please call moveToNext() to get latest calling event.


   1: class CalllogObserver extends ContentObserver
   2: {       
   3:     public CalllogObserver(Handler handler) 
   4:     {
   5:             super(handler);
   6:         }
   7:  
   8:         public void onChange(boolean bSelfChange)
   9:     {    
  10:         super.onChange(bSelfChange);
  11:         
  12:                 Cursor c = m_context.getContentResolver().query(CallLog.Calls.CONTENT_URI, null, null, null, null);
  13:                 c.moveToLast(); //point to latest message! different to the sms, the latest call log was appened at the end of list
  14:                 
  15:                 String callStartTime = c.getString(c.getColumnIndex("date"));
  16:                 String callDuration = c.getString(c.getColumnIndex("duration"));
  17:                 String callType = c.getString(c.getColumnIndex("type")); // 1,incoming; 2,outgoing; 3,missed
  18:                 String callTarget = c.getString(c.getColumnIndex("number"));
  19:         }
  20: }
  21:  
  22: ContentResolver contentResolver = m_context.getContentResolver();
  23: Handler handler = new Handler();
  24: ContentObserver m_CalllogObserver = new CalllogObserver(handler);
  25: contentResolver.registerContentObserver(CallLog.Calls.CONTENT_URI, true, m_CalllogObserver);


   1: class SMSObserver extends ContentObserver
   2: {       
   3:     public SMSObserver(Handler handler) {
   4:         super(handler);
   5:     }
   6:  
   7:     public void onChange(boolean bSelfChange)
   8:     {    
   9:         super.onChange(bSelfChange);
  10:         Logger.e(TAG, "sms db changed");  
  11:  
  12:         String strUriInbox = "content://sms/";
  13:         Uri uriSms = Uri.parse(strUriInbox); 
  14:         Cursor c = m_context.getContentResolver().query(uriSms, null, null, null, null);
  15:         c.moveToNext(); //point to latest message!
  16:  
  17:         
  18:         int smsType = Integer.valueOf(c.getString(c.getColumnIndex("type")));
  19:         
  20:         if (smsType == 1 || smsType == 2) //inbox and sent
  21:         {
  22:             boolean bReceived = (smsType == 1) ? true : false;            
  23:             String smsTime = c.getString(c.getColumnIndex("date"));
  24:             String smsBody = c.getString(c.getColumnIndex("body"));
  25:             String smsAddress = c.getString(c.getColumnIndex("address"));
  26:         }
  27:         else
  28:         {
  29:             //DO NOTHINg
  30:             Logger.d(TAG, "skip non-inbox non-sent");
  31:         }
  32:         c.close();
  33:     }
  34: }
  35:  
  36: ContentResolver contentResolver = m_context.getContentResolver();
  37: Handler handler = new Handler();
  38: ContentObserver m_SMSObserver = new SMSObserver(handler);
  39: contentResolver.registerContentObserver(Uri.parse("content://sms/"), true, m_SMSObserver);

Wednesday, December 7, 2011

Query contact name by phone number (Android)

   1: public static String queryNamebyNumber(ContentResolver cr,String number)
   2: {
   3:     String[] projection = new String[] {
   4:             ContactsContract.PhoneLookup.DISPLAY_NAME,  
   5:             ContactsContract.CommonDataKinds.Phone.NUMBER
   6:          }; 
   7:  
   8:     // Make the query. 
   9:     Cursor cur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI
  10:                              ,projection // Which columns to return
  11:                              ,ContactsContract.CommonDataKinds.Phone.NUMBER + "=?"
  12:                              ,new String[]{number}
  13:                              ,null);
  14:     
  15:     String numberOwner = "";
  16:      if (cur.moveToFirst()) 
  17:      {
  18:         int nameColumn = cur.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME); 
  19:         do {
  20:             String name = cur.getString(nameColumn);               
  21:             if (name != null)
  22:                 numberOwner += (name + "|||");
  23:         } while (cur.moveToNext());            
  24:      }
  25:      Logger.d(TAG, "number owner:" + numberOwner);
  26:      
  27:     cur.close();
  28:     return numberOwner;
  29: }

Something we should care, the format symbol:


When a contact was synced from Google Contacts, the phone number within the contact was totally same as you typed in Google Contacts. No “-” would been added! number “4081234567” will not be formatted to “408-123-4567”!


While you add a contact on the phone(maybe some models), when you type “4081234567”. “408-123-4567” will saved as the number.


So, if you’re going to make a smart phone number query, you’d better process the “-” symbol.