Biometric not working when executing the CLI from java

pierrebeitz
pierrebeitz
Community Member

Hello

I'm building a java CLI that wraps op for some operations.
The issue was first observed when running a native binary compiled with Graalvm, but after investigation it is perfectly reproducible using pure java (but not the system java for some reason).

Reproducing

  • Ubuntu 20.04.1
  • 1Password for Linux 8.7.3
  • CLI 2.5.1 configured to support Biometric authentication as per https://developer.1password.com/docs/cli/get-started/#sign-in
  • Sign up to the account with op sign in, verify you can list your vaults: op vault ls.
  • create the following file and compile it with javac (javac Op.java):
// Op.java
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class Op {

    public static void main(String args[]) throws IOException {
        List<String> commands = Arrays.asList("op", "vault", "ls");
        call(commands);
    }

    private static Process call(List<String> args) throws IOException {
        ProcessBuilder pb = new ProcessBuilder(args)
            .redirectErrorStream(true)
            .directory(new File(System.getProperty("user.dir")));
        pb.inheritIO();
        return execute(pb);
    }

    private static Process execute(ProcessBuilder pb) throws IOException {
        var p = pb.start();
        try {
            p.waitFor();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return p;
    }

}
  • Run the compiled class with java Op. If you are using the system java (installed with apt install ...) it should be a success, but if you are using a java that is not the system java you will see an issue. For instance, I managed to reproduce the issue running a java installed with asdf. You will see something similar too:
[ERROR] 2022/07/18 12:34:12 connecting to desktop app: connection reset, make sure the CLI is correctly installed and CLI Biometric Unlock is enabled in the 1Password app

Looking into systemctl one can see:

Jul 18 12:46:13 *** polkitd(authority=local)[42243]: Operator of unix-session:c1 FAILED to authenticate to gain authorization for action com.1password.1Password.authorizeCLI for unix-process:36645:669364 [/opt/1Password/1password --enable-crashpad] (owned by unix-user:***)

and:

Jul 18 12:47:13 *** 1password.desktop[36645]: WARN  2022-07-18T12:47:13.840 tokio-runtime-worker(ThreadId(2)) [1P:foundation/op-sys-info/src/process_information/linux.rs:247] binary permission verification failed for /home/$USER/.asdf/installs/java/temurin-11.0.15+10/bin/java

The second line is also visible in 1password logs.

Additional notes

  • This works ok on osX.
  • I'm not set on whether the issue is on 1password client side (as it seems there is a check on the binary) or on Polkit side.
  • The original issue was with a binary compiled with Graalvm, but the symptoms and logs are exactly the same with this minimal example. If needed I can build a minimal reproduction case with a Graalvm native binary though.

1Password Version: 8.7.3
Extension Version: 2.5.1
OS Version: Ubuntu 20.04.1
Browser:_ Not Provided

Comments

  • pierrebeitz
    pierrebeitz
    Community Member

    Hello

    I'm building a java CLI that wraps op for some operations.
    The issue was first observed when running a native binary compiled with Graalvm, but after investigation it is perfectly reproducible using pure java (but not the system java for some reason).

    Reproducing

    • Ubuntu 20.04.1
    • 1Password for Linux 8.7.3
    • CLI 2.5.1 configured to support Biometric authentication as per https://developer.1password.com/docs/cli/get-started/#sign-in
    • Sign up to the account with op sign in, verify you can list your vaults: op vault ls.
    • create the following file and compile it with javac (javac Op.java):
    // Op.java
    import java.io.File;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.List;
    
    public class Op {
    
        public static void main(String args[]) throws IOException {
            List<String> commands = Arrays.asList("op", "vault", "ls");
            call(commands);
        }
    
        private static Process call(List<String> args) throws IOException {
            ProcessBuilder pb = new ProcessBuilder(args)
                .redirectErrorStream(true)
                .directory(new File(System.getProperty("user.dir")));
            pb.inheritIO();
            return execute(pb);
        }
    
        private static Process execute(ProcessBuilder pb) throws IOException {
            var p = pb.start();
            try {
                p.waitFor();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return p;
        }
    
    }
    
    • Run the compiled class with java Op. If you are using the system java (installed with apt install ...) it should be a success, but if you are using a java that is not the system java you will see an issue. For instance, I managed to reproduce the issue running a java installed with asdf. You will see something similar too:
    [ERROR] 2022/07/18 12:34:12 connecting to desktop app: connection reset, make sure the CLI is correctly installed and CLI Biometric Unlock is enabled in the 1Password app
    

    Looking into systemctl one can see:

    Jul 18 12:46:13 *** polkitd(authority=local)[42243]: Operator of unix-session:c1 FAILED to authenticate to gain authorization for action com.1password.1Password.authorizeCLI for unix-process:36645:669364 [/opt/1Password/1password --enable-crashpad] (owned by unix-user:***)
    

    and:

    Jul 18 12:47:13 *** 1password.desktop[36645]: WARN  2022-07-18T12:47:13.840 tokio-runtime-worker(ThreadId(2)) [1P:foundation/op-sys-info/src/process_information/linux.rs:247] binary permission verification failed for /home/$USER/.asdf/installs/java/temurin-11.0.15+10/bin/java
    

    The second line is also visible in 1password logs.

    Additional notes

    • This works ok on osX.
    • I'm not set on whether the issue is on 1password client side (as it seems there is a check on the binary) or on Polkit side.
    • The original issue was with a binary compiled with Graalvm, but the symptoms and logs are exactly the same with this minimal example. If needed I can build a minimal reproduction case with a Graalvm native binary though.
  • Hey @pierrebeitz ,

    Thank you for reaching out to us!
    I think you just uncovered a bug :D The issue here seems to be that the 1Password application enforces, on Linux, that the parent caller of the CLI would be owned by root. While in a normal use-case, such as making a CLI command from bash, this would not become apparent, it seems that in this case, since the /home/$USER/.asdf/installs/java/temurin-11.0.15+10/bin/java file is most likely not owned by root, it does not pass this check.

    Although I do not have a Linux system to run local tests on and to try to reproduce this issue, there are a couple of things that come to mind that you could try, in order to try to address this problem:

    • prefix the op command by /bin/bash -c. This should ensure that the parent of the op command is bash, which is owned already by root
    • try changing the ownership of your java build to root, or install an alternative java version to be owned by root

    These being said, we do realise that this is indeed not in line with what happens on the other OS's, and, from a security standpoint, it does not bring too much to the table, so I have opened an internal ticket for investigating getting rid of this check. I'll make sure to update you when any developments are made there. In the meantime, please, let us know if any of the workarounds from above would work for you. Otherwise, I'm going to set up a VM with a test environment, where hopefully I'll be able to come up with new ideas.

    Looking forward to hearing from you!
    Best,
    Horia

  • pierrebeitz
    pierrebeitz
    Community Member

    Hello @Horia.Culea_1P

    Thanks for your answer. Sadly none of the proposed workarounds seem to change a thing:

    • Modifying the java code like this: List<String> commands = Arrays.asList("/bin/bash", "-c", "op vault ls"); I observe the same error message and the same log in journalctl.
    • Modifying the binary permission, I observe the same error message and the same log in journalctl.

    Error message:

    [ERROR] 2022/07/21 09:16:04 connecting to desktop app: connection reset, make sure the CLI is correctly installed and CLI Biometric Unlock is enabled in the 1Password app
    

    Log:

    Jul 21 09:16:04 *** 1password.desktop[4511]: WARN  2022-07-21T09:16:04.984 tokio-runtime-worker(ThreadId(1)) [1P:foundation/op-sys-info/src/process_information/linux.rs:247] binary permission verification failed for /home/$USER/.asdf/installs/java/temurin-11.0.15+10/bin/java
    

    Just to be aligned on the permissions:

    $ ls -al /home/$USER/.asdf/installs/java/temurin-11.0.15+10/bin/java
    -rwxr-xr-x 1 root root 12768 Apr 19 21:38 /home/***/.asdf/installs/java/temurin-11.0.15+10/bin/java
    

    And for the sake of completeness, I even ran chmod 777 /home/$USER/.asdf/installs/java/temurin-11.0.15+10/bin/java to make sure I wasn't missing another linux permission. This resulted in the exact same error and log.
    I must admit I'm getting curious about this line src/process_information/linux.rs:247 :)

    Regards

  • Hey @pierrebeitz !

    Apologies for the late reply here. I have an idea of what could be happening here. Could you maybe try a slight variation of the /bin/bash -c workaround?

    1. Create a file op.sh with the following content:
    #!/bin/bash
    op ${@}
    
    1. chmod +x ./op.sh
    2. Replace op with op.sh in your Java code.

    I would expect this to do the trick because in contrast to /bin/bash -c, the above script does spawn op as a child of bash. That should satisfy the existing security check.

    I must admit I'm getting curious about this line src/process_information/linux.rs:247 :)

    Haha, so would I! It's actually a security check that existed before the CLI integration was built and this code was only used by our browser extensions. It still exists because taking out a security check is not easy and until now, it has never caused any problems. Now that we know it can cause some problems, we will re-evaluate whether it is still required. However, because we err on the side of caution when it comes to security, I cannot make any commitments on if and when this will happen if we can find a workaround.

    Let me know if the above workaround fixes the problem!

    Joris

  • apapai
    apapai
    Community Member

    This seems to work.

  • pierrebeitz
    pierrebeitz
    Community Member

    Hello @Joris_1P

    Sorry for the delay. I confirm the provided workaround works.
    Thanks for the detailed answer about the legacy reasons for the security check.

    Pierre

  • Glad we could help!

This discussion has been closed.