1 /*
2 This is free and unencumbered software released into the public domain.
3
4 Anyone is free to copy, modify, publish, use, compile, sell, or
5 distribute this software, either in source code form or as a compiled
6 binary, for any purpose, commercial or non-commercial, and by any
7 means.
8
9 In jurisdictions that recognize copyright laws, the author or authors
10 of this software dedicate any and all copyright interest in the
11 software to the public domain. We make this dedication for the benefit
12 of the public at large and to the detriment of our heirs and
13 successors. We intend this dedication to be an overt act of
14 relinquishment in perpetuity of all present and future rights to this
15 software under copyright law.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24
25 For more information, please refer to <http://unlicense.org/>
26 */
27
28 #include <dse.h>
29 #include <stdio.h>
30
31 /*
32 * This example program assumes that the following setup is done in DSE apriori:
33 *
34 * 1. DSE is configured to authenticate with Kerberos.
35 * 2. Using cqlsh as an administrator user (e.g. cassandra), create the following
36 * objects and grant permissions for them:
37 *
38 CREATE ROLE target_user WITH PASSWORD = 'target_user' and LOGIN = true;
39 CREATE KEYSPACE examples WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor':
40 1}; CREATE TABLE examples.gss_proxy_auth (f1 int PRIMARY KEY, f2 int); INSERT INTO
41 examples.gss_proxy_auth (f1, f2) VALUES (1, 2); GRANT ALL ON examples.gss_proxy_auth TO
42 target_user;
43
44 GRANT PROXY.LOGIN ON ROLE 'target_user' to 'dseuser@DATASTAX.COM';
45 *
46 * Substitute your own Kerberos user for 'dseuser@DATASTAX.COM' (in the above cql and
47 * the KERBEROS_USER macro below).
48 *
49 * Note that proxy auth can target an internal user (e.g. target_user) even if the authenticated
50 * user is from Kerberos.
51 */
52
53 #define KERBEROS_USER "dseuser@DATASTAX.COM"
54
print_error(CassFuture * future)55 void print_error(CassFuture* future) {
56 const char* message;
57 size_t message_length;
58 cass_future_error_message(future, &message, &message_length);
59 fprintf(stderr, "Error: %.*s\n", (int)message_length, message);
60 }
61
select_and_dump(CassSession * session)62 CassError select_and_dump(CassSession* session) {
63 CassError rc = CASS_OK;
64 CassStatement* statement = NULL;
65 CassFuture* future = NULL;
66 const char* query = "SELECT * FROM examples.gss_proxy_auth";
67
68 statement = cass_statement_new(query, 0);
69 future = cass_session_execute(session, statement);
70
71 rc = cass_future_error_code(future);
72 if (rc != CASS_OK) {
73 print_error(future);
74 } else {
75 const CassResult* result = cass_future_get_result(future);
76 CassIterator* iterator = cass_iterator_from_result(result);
77
78 if (cass_iterator_next(iterator)) {
79 int f1, f2;
80 const CassRow* row = cass_iterator_get_row(iterator);
81 if (cass_value_get_int32(cass_row_get_column(row, 0), &f1) != CASS_OK ||
82 cass_value_get_int32(cass_row_get_column(row, 1), &f2) != CASS_OK) {
83 print_error(future);
84 } else {
85 printf("f1: %d f2: %d\n", f1, f2);
86 }
87 }
88
89 cass_result_free(result);
90 cass_iterator_free(iterator);
91 }
92
93 cass_future_free(future);
94 cass_statement_free(statement);
95
96 return rc;
97 }
98
connect_session(CassSession * session,const CassCluster * cluster)99 CassError connect_session(CassSession* session, const CassCluster* cluster) {
100 CassError rc = CASS_OK;
101 CassFuture* future = cass_session_connect(session, cluster);
102
103 rc = cass_future_error_code(future);
104 if (rc != CASS_OK) {
105 print_error(future);
106 }
107 cass_future_free(future);
108
109 return rc;
110 }
111
connect_and_run(const char * hosts,const char * proxy_user)112 void connect_and_run(const char* hosts, const char* proxy_user) {
113 CassCluster* cluster = cass_cluster_new();
114 CassSession* session = cass_session_new();
115
116 /* Add contact points */
117 cass_cluster_set_contact_points(cluster, hosts);
118
119 /* Hostname resolution is typically necessary when authenticating with Kerberos. */
120 cass_cluster_set_use_hostname_resolution(cluster, cass_true);
121
122 /* Authenticate as the Kerberos user. If proxy_user is non-null,
123 * declare that we want to execute all statements as proxy_user. */
124 if (proxy_user == NULL) {
125 cass_cluster_set_dse_gssapi_authenticator(cluster, "dse", KERBEROS_USER);
126 } else {
127 cass_cluster_set_dse_gssapi_authenticator_proxy(cluster, "dse", KERBEROS_USER, "target_user");
128 }
129
130 if (connect_session(session, cluster) != CASS_OK) {
131 cass_cluster_free(cluster);
132 cass_session_free(session);
133 return;
134 }
135
136 select_and_dump(session);
137
138 cass_cluster_free(cluster);
139 cass_session_free(session);
140 }
141
main(int argc,char * argv[])142 int main(int argc, char* argv[]) {
143 /* Setup and connect to cluster */
144 char* hosts = "127.0.0.1";
145 if (argc > 1) {
146 hosts = argv[1];
147 }
148
149 /* Enable info logging if desired. */
150 /* cass_log_set_level(CASS_LOG_INFO); */
151
152 printf("Running a query without a proxy user should fail:\n");
153 connect_and_run(hosts, NULL);
154 printf("\nRunning a query with proxy user 'target_user' should succeed:\n");
155 connect_and_run(hosts, "target_user");
156
157 return 0;
158 }
159