Skip to content

Commit e93e5b3

Browse files
committed
Add simple CLI for creating tokens.
1 parent 21c8d85 commit e93e5b3

File tree

2 files changed

+202
-0
lines changed

2 files changed

+202
-0
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ find_package( OpenSSL REQUIRED )
2626
find_package( Sqlite3 REQUIRED )
2727
set(LIBCRYPTO_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR})
2828
set(LIBCRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
29+
set(CMAKE_MACOSX_RPATH ON)
2930

3031
elseif( UNIX )
3132

@@ -60,6 +61,9 @@ target_link_libraries(scitokens-test-access SciTokens)
6061
add_executable(scitokens-list-access src/list_access.cpp)
6162
target_link_libraries(scitokens-list-access SciTokens)
6263

64+
add_executable(scitokens-create src/create.cpp)
65+
target_link_libraries(scitokens-create SciTokens)
66+
6367
if (NOT DEFINED LIB_INSTALL_DIR)
6468
SET(LIB_INSTALL_DIR "lib")
6569
endif()

src/create.cpp

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
2+
#include "scitokens.h"
3+
4+
#include <stdlib.h>
5+
#include <getopt.h>
6+
7+
#include <cstdio>
8+
#include <string>
9+
#include <vector>
10+
#include <fstream>
11+
12+
namespace {
13+
14+
const char usage[] = \
15+
"\n"
16+
"Syntax: %s [--cred cred_file] [--key key_file] [--keyid kid]\n"
17+
" [--claim key=val] ...\n"
18+
"\n"
19+
" Options\n"
20+
" -h | --help Display usage\n"
21+
" -c | --cred <cred_file> File containing signing credential.\n"
22+
" -k | --key <key_file> File containing the signing private key.\n"
23+
" -K | --keyid <kid> Name of the token key.\n"
24+
" -i | --issuer <issuer> Issuer for the token.\n"
25+
" -p | --profile <profile> Token profile (wlcg, scitokens1, scitokens2).\n"
26+
"\n";
27+
28+
const struct option long_options[] =
29+
{
30+
{"help", no_argument, NULL, 'h'},
31+
{"cred", required_argument, NULL, 'c'},
32+
{"key", required_argument, NULL, 'k'},
33+
{"keyid", required_argument, NULL, 'K'},
34+
{"issuer", required_argument, NULL, 'i'},
35+
{"claim", required_argument, NULL, 'C'},
36+
{"profile", required_argument, NULL, 'p'},
37+
{0, 0, 0, 0}
38+
};
39+
40+
const char short_options[] = "hc:k:K:i:C:p:";
41+
42+
std::string g_cred, g_key, g_kid, g_issuer, g_profile;
43+
std::vector<std::string> g_claims;
44+
45+
int init_arguments(int argc, char *argv[]) {
46+
47+
int arg;
48+
while((arg = getopt_long(argc, argv, short_options, long_options, nullptr)) != -1)
49+
{
50+
switch (arg)
51+
{
52+
case 'h':
53+
printf(usage, argv[0]);
54+
exit(0);
55+
break;
56+
case 'c':
57+
g_cred = optarg;
58+
break;
59+
case 'k':
60+
g_key = optarg;
61+
break;
62+
case 'K':
63+
g_kid = optarg;
64+
break;
65+
case 'i':
66+
g_issuer = optarg;
67+
break;
68+
case 'C':
69+
g_claims.emplace_back(optarg);
70+
break;
71+
case 'p':
72+
g_profile = optarg;
73+
break;
74+
default:
75+
fprintf(stderr, usage, argv[0]);
76+
exit(1);
77+
break;
78+
}
79+
}
80+
81+
if (optind != argc) {
82+
fprintf(stderr, "%s: invalid option -- %s\n", argv[0], argv[optind]);
83+
fprintf(stderr, usage, argv[0]);
84+
exit(1);
85+
}
86+
87+
if (g_cred.empty()) {
88+
fprintf(stderr, "%s: missing --cred option\n", argv[0]);
89+
fprintf(stderr, usage, argv[0]);
90+
exit(1);
91+
}
92+
93+
if (g_key.empty()) {
94+
fprintf(stderr, "%s: missing --key option\n", argv[0]);
95+
fprintf(stderr, usage, argv[0]);
96+
exit(1);
97+
}
98+
99+
if (g_kid.empty()) {
100+
fprintf(stderr, "%s: missing --keyid option\n", argv[0]);
101+
fprintf(stderr, usage, argv[0]);
102+
exit(1);
103+
}
104+
105+
if (g_issuer.empty()) {
106+
fprintf(stderr, "%s: missing --issuer option\n", argv[0]);
107+
fprintf(stderr, usage, argv[0]);
108+
exit(1);
109+
}
110+
111+
return 0;
112+
}
113+
114+
}
115+
116+
int main(int argc, char *argv[]) {
117+
118+
int rv = init_arguments(argc, argv);
119+
if (rv) {
120+
return rv;
121+
}
122+
123+
std::ifstream priv_ifs(g_key);
124+
std::string private_contents( (std::istreambuf_iterator<char>(priv_ifs)),
125+
(std::istreambuf_iterator<char>())
126+
);
127+
std::ifstream pub_ifs(g_cred);
128+
std::string public_contents( (std::istreambuf_iterator<char>(pub_ifs)),
129+
(std::istreambuf_iterator<char>())
130+
);
131+
132+
char *err_msg;
133+
auto key_raw = scitoken_key_create(g_kid.c_str(), "ES256", public_contents.c_str(),
134+
private_contents.c_str(), &err_msg);
135+
std::unique_ptr<void, decltype(&scitoken_key_destroy)>
136+
key(key_raw, scitoken_key_destroy);
137+
if (key_raw == nullptr) {
138+
fprintf(stderr, "Failed to generate a key: %s\n", err_msg);
139+
free(err_msg);
140+
return 1;
141+
}
142+
143+
std::unique_ptr<void, decltype(&scitoken_destroy)>
144+
token(scitoken_create(key_raw), scitoken_destroy);
145+
if (token.get() == nullptr) {
146+
fprintf(stderr, "Failed to generate a new token.\n");
147+
return 1;
148+
}
149+
150+
rv = scitoken_set_claim_string(token.get(), "iss", g_issuer.c_str(), &err_msg);
151+
if (rv) {
152+
fprintf(stderr, "Failed to set issuer: %s\n", err_msg);
153+
free(err_msg);
154+
return 1;
155+
}
156+
157+
for (const auto &claim : g_claims) {
158+
auto pos = claim.find("=");
159+
if (pos == std::string::npos) {
160+
fprintf(stderr, "Claim must contain a '=' character: %s\n", claim.c_str());
161+
return 1;
162+
}
163+
auto key = claim.substr(0, pos);
164+
auto val = claim.substr(pos + 1);
165+
166+
rv = scitoken_set_claim_string(token.get(), key.c_str(), val.c_str(), &err_msg);
167+
if (rv) {
168+
fprintf(stderr, "Failed to set claim (%s=%s): %s\n", key.c_str(), val.c_str(), err_msg);
169+
free(err_msg);
170+
return 1;
171+
}
172+
}
173+
174+
if (!g_profile.empty()) {
175+
SciTokenProfile profile;
176+
if (g_profile == "wlcg") {
177+
profile = SciTokenProfile::WLCG_1_0;
178+
} else if (g_profile == "scitokens1") {
179+
profile = SciTokenProfile::SCITOKENS_1_0;
180+
} else if (g_profile == "scitokens2") {
181+
profile = SciTokenProfile::SCITOKENS_2_0;
182+
} else {
183+
fprintf(stderr, "Unknown token profile: %s\n", g_profile.c_str());
184+
return 1;
185+
}
186+
scitoken_set_serialize_mode(token.get(), profile);
187+
}
188+
189+
char *value;
190+
rv = scitoken_serialize(token.get(), &value, &err_msg);
191+
if (rv) {
192+
fprintf(stderr, "Failed to serialize the token: %s\n", err_msg);
193+
free(err_msg);
194+
return 1;
195+
}
196+
197+
printf("%s\n", value);
198+
}

0 commit comments

Comments
 (0)