javawindows-servicesjava-service-wrapper

How to detect a user login using Java Service Wrapper


I have created a Java application and used Java Service Wrapper method 3 that implements the WrapperListener to convert it to a Windows Service.

The WrapperManager can be used to identify various events that get raised and caught in the wrapper listener controlEvent function, this includes a user logging off, however doesn't have a user login event.

Is there a way I can detect a user logging in to the system and perform some kind of action in my Java application? If not, is there a way to detect a spike in CPU usage that I can use to make an assumption of a user logging in? This is required because my application needs to perform some action when a user logs in.


Solution

  • There is no logon control code for user logons within the Service Control Manager. Additionally Java Service Wrapper makes use of common control signals. It would not make much sense to have a CTRL_LOGON_EVENT when working with event handling: https://msdn.microsoft.com/en-us/library/windows/desktop/ms683242.aspx

    You might need to consider looking around in the Windows Event Log for event id 4648 under Security and programming an implementation of event subscription but it will require an understanding of Windows APIs and the usage of the Java Native Access library:

    https://msdn.microsoft.com/en-us/library/windows/desktop/aa385771.aspx

    The workaround above is not ideal but it's a possible route.

    A bit more information about the service you're working on would really help.

    EDIT:

    On user login, this program should run as the user, (refer at bottom for the command):

    LoginServiceDefer.java

    import org.tanukisoftware.wrapper.WrapperManager;
    
    public class LoginServiceDefer {
        public static String svc = "loginservice";
        public static int ctrl   = 155;
    
        public static void main(String[] args) {
            System.out.println("Sending user control code.");
            try {
                WrapperManager.sendServiceControlCode(svc, ctrl);
                WrapperManager.stop(0);
            } catch (Exception re) {
                System.err.println("System error. Unable to send control code to service, " + svc + ", with control code, " + ctrl + ".");
                re.printStackTrace();
                WrapperManager.stop(1);
            }
        }
    }
    

    This is the listener that will be used in your service. It runs as SYSTEM:

    LoginListener.java

    import org.tanukisoftware.wrapper.event.WrapperEvent;
    import org.tanukisoftware.wrapper.event.WrapperEventListener;
    import org.tanukisoftware.wrapper.event.WrapperServiceControlEvent;
    
    
    public class LoginListener implements WrapperEventListener
    {
        public LoginListener() { }
    
        public void fired( WrapperEvent event ) {
            if (event instanceof WrapperServiceControlEvent) {
                WrapperServiceControlEvent scEvent = (WrapperServiceControlEvent) event;
                switch (scEvent.getServiceControlCode()) {
                    case 155:
                        // LoginServiceDefer has sent a control code.
                        break;
                }
            }
        }
    }
    

    Add this line before WrapperManager.start()

    WrapperManager.addWrapperEventListener(new LoginListener(), WrapperEventListener.EVENT_FLAG_SERVICE);
    

    Add these two lines to your wrapper.conf

    wrapper.java.additional.1=-Djava.security.manager
    wrapper.java.additional.2=-Djava.security.policy=java.policy
    

    Create a new file called java.policy.

    Place it in the folder where Wrapper.exe is located (should be wrapper-windows/bin/wrapper.exe).

    // NOTE: There are ways of limiting the permissions for the notifier using the the library.
    grant codeBase "file:../lib/wrapper.jar" {
            permission java.security.AllPermission;
    };
    
    // Change *my_login_notifier.jar* to whatever LoginServiceDefer.java is as a jar.
    grant codeBase "file:./*my_login_notifier.jar*" {
            permission java.security.AllPermission;
    };
    

    Run this command on user login, making sure to cd to the path or edit the java.policy file:

    java -Djava.security.manager -Djava.security.policy=java.policy -jar *my_login_notifier.jar*.jar