Skip to content
This repository was archived by the owner on May 4, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions v2client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
<artifactId>commons-codec</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
<build>
<resources>
Expand Down
187 changes: 162 additions & 25 deletions v2client/src/main/java/com/yubico/client/v2/Cmd.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/* Copyright (c) 2011, Linus Widströmer. All rights reserved.
/* Copyright (c) 2016, Nicholas Sushkin. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
Expand All @@ -26,37 +26,174 @@ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

Written by Linus Widströmer <[email protected]>, January 2011.
Written by Nicholas Sushkin <[email protected]>, August 2016.
*/

package com.yubico.client.v2;

import com.yubico.client.v2.exceptions.*;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.ParseException;

public class Cmd {

public static void main (String args []) throws Exception
{
if (args.length != 3) {
System.err.println("\n*** Test your Yubikey against Yubico OTP validation server ***");
System.err.println("\nUsage: java -jar client.jar Client_ID Client_key OTP");
System.err.println("\nEg. java -jar client.jar 28 vvfucnlcrrnejlbuthlktguhclhvegbungldcrefbnku");
System.err.println("\nTouch Yubikey to generate the OTP. Visit Yubico.com for more details.");
return;
}
static Options options = new Options()
.addOption("h", "help", false, "Display this help screen")
.addOption("V", "version", false, "Display version information")
.addOption("d", "debug", false, "Print debugging information")
.addOption(Option.builder("a").longOpt("apikey").hasArg().desc("API key for HMAC validation of request/response").argName("key").build())
.addOption(Option.builder("u").longOpt("url").hasArg().desc("Yubikey validation service URL").argName("ykvalurl").build());

String otp = args[2];
static void printUsage() {
(new HelpFormatter()).printHelp("java -jar client.jar (--help|--version|--apikey <key>) [--debug] [--url <ykvalurl>]* CLIENTID YUBIKEYOTP\n" +
"or: java -jar client.jar [--debug] [--url <ykvalurl>]* CLIENTID key YUBIKEYOTP",
"Validate the YUBIKEYOTP one-time-password against the YubiCloud using CLIENTID as the client identifier\n\n",
options,
"\nExit status is 0 on success, 1 if there is a hard failure, 2 if the OTP was replayed, 3 for other soft OTP-related failures.");
}

YubicoClient yc = YubicoClient.getClient(Integer.parseInt(args[0]), args[1]);
VerificationResponse response = yc.verify(otp);
static String getVersion() {
return Cmd.class.getName() + " " + Version.version;
}

if(response!=null && response.getStatus() == ResponseStatus.OK) {
System.out.println("\n* OTP verified OK");
} else {
System.out.println("\n* Failed to verify OTP");
static void log(String description, String value) {
if (value != null) {
System.err.printf("%14s: %s\n", description, value);
}
}

public static void main (String args[]) throws Exception {
CommandLineParser parser = new DefaultParser();

try {
CommandLine cli = parser.parse(options, args, true);

String[] leftoverArgs = cli.getArgs();

if ( cli.hasOption("h") ) {
printUsage();
return;
}

if ( cli.hasOption("V") ) {
System.out.println(getVersion());
return;
}

if ( ( leftoverArgs.length < 2 )
|| ( leftoverArgs.length > 3 )
) {
printUsage();
return;
}

boolean legacyUsage = (leftoverArgs.length == 3);

if ( ! legacyUsage && ! cli.hasOption("a") ) {
System.err.println("Specify API key using --apikey key option");
System.exit(1);
}

System.out.println("\n* Last response: " + response);
System.exit(0);
int clientId = -1;
try {
clientId = Integer.parseInt(leftoverArgs[0]);
} catch (NumberFormatException e) {
System.err.println("error: client identity must be a positive integer.");
System.exit(1);
}

} // End of main
if (clientId <= 0) {
System.err.println("error: client identity must be a positive integer.");
System.exit(1);
}

String apiKey = legacyUsage ? leftoverArgs[1] : cli.getOptionValue("a");
String otp = legacyUsage ? leftoverArgs[2] : leftoverArgs[1];

YubicoClient yc = YubicoClient.getClient(clientId, apiKey);

yc.setUserAgent(getVersion());

if ( cli.hasOption("u") ) {
yc.setWsapiUrls( cli.getOptionValues("u") );
}

if (otp.length() < 32) {
System.err.println("error: modhex encoded token must be at least 32 characters");
System.exit(1);
}

if ( cli.hasOption("d") ) {
System.err.printf("%s:\n", "Input");
for ( String url: yc.getWsapiUrls() )
{
System.err.printf("%14s: %s\n", "validation URL", url);
}
log("client id", Integer.toString(yc.getClientId()));
log("token", otp);
log("api key", yc.getKey());
}

try {
VerificationResponse response = yc.verify(otp);
ResponseStatus status = response.getStatus();

if ( cli.hasOption("d") ) {
System.err.printf("\n%s: %s\n", "Response", response);

if (status != null) {
System.err.printf("%14s: (%d) %s\n", "status", status.ordinal(), status);
}

log("otp", response.getOtp());
log("nonce", response.getNonce());
log("t", response.getT());
log("timestamp", response.getTimestamp());
log("sessioncounter", response.getSessioncounter());
log("sessionuse", response.getSessionuse());
log("sl", response.getSl());
}

if (legacyUsage) {
if (response.isOk()) {
System.out.println("\n* OTP verified OK");
} else {
System.out.println("\n* Failed to verify OTP");
}
}

if (response.isOk()) {
System.exit(0);
} else if (status == ResponseStatus.REPLAYED_OTP) {
System.exit(2);
} else {
System.exit(3);
}
}
catch (YubicoVerificationException e) {
System.err.println("Validation Error: " + e);
System.exit(3);
}
catch (YubicoValidationFailure f) {
System.err.println("Validation Failure: " + f);
System.exit(3);
}
catch (IllegalArgumentException a) {
System.err.println("Incorrectly formatted OTP string: " + a);
System.exit(3);
}

return;
}
catch (ParseException pe) {
System.err.println("Error parsing command line: " + pe.getMessage());
System.exit(1);
}
}
}