Skip to content

Commit 3ce178b

Browse files
author
Yashwant Sahu
committed
After hash pin
1 parent 3e8c845 commit 3ce178b

File tree

5 files changed

+538
-0
lines changed

5 files changed

+538
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
2+
INCLUDE(CheckIncludeFiles)
3+
4+
IF (NOT CMAKE_SYSTEM_NAME MATCHES "Win")
5+
CHECK_INCLUDE_FILES(sasl/sasl.h HAVE_SASL_H)
6+
CHECK_INCLUDE_FILES(lber.h HAVE_LBER_H)
7+
IF(HAVE_SASL_H)
8+
SET(CMAKE_EXTRA_INCLUDE_FILES sasl/sasl.h)
9+
ENDIF()
10+
IF(HAVE_LBER_H)
11+
SET(CMAKE_EXTRA_INCLUDE_FILES lber.h)
12+
ENDIF()
13+
IF(NOT HAVE_SASL_H)
14+
MESSAGE(STATUS "Required SASL library is missing. Skipping the LDAP authentication plugin.")
15+
RETURN()
16+
ENDIF()
17+
IF(NOT HAVE_LBER_H)
18+
MESSAGE(STATUS "Required LBER library is missing. Skipping the LDAP authentication plugin.")
19+
RETURN()
20+
ENDIF()
21+
ENDIF()
22+
23+
# LDAP authentication SASL client will not build on windows, as windows don't have cyrus sasl.
24+
# IF someone like can build the cyrus sasl library on windows and build LDAP authentication sasl client as well.
25+
IF (NOT CMAKE_SYSTEM_NAME MATCHES "Win")
26+
SET(HEADERS_CLIENT auth_ldap_sasl_client.h log.h)
27+
SET(PLUGIN_CLIENT_SOURCES auth_ldap_sasl_client.cc log.cc)
28+
29+
ADD_CONVENIENCE_LIBRARY(authentication_ldap_sasl_client ${PLUGIN_CLIENT_SOURCES} ${HEADERS_CLIENT})
30+
TARGET_LINK_LIBRARIES(authentication_ldap_sasl_client sasl2)
31+
ENDIF()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
2+
3+
#include "auth_ldap_sasl_client.h"
4+
#include <string.h>
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
#ifndef _WIN32
8+
#include <lber.h>
9+
#include <sasl/sasl.h>
10+
#endif
11+
#include <mysql/client_plugin.h>
12+
#include <mysql.h>
13+
14+
#define LDAP_LOG_INTO_FILE // Will add compile time option for this varaible
15+
#ifdef LDAP_LOG_INTO_FILE
16+
// Log into external log file
17+
Logger<Log_writer_file> g_logger("ldap_log_client.txt");
18+
#else
19+
// This will be redirect to error stream
20+
Logger<Log_writer_error> g_logger("");
21+
#endif
22+
23+
void Sasl_client::Interact(sasl_interact_t *ilist) {
24+
while(ilist->id != SASL_CB_LIST_END) {
25+
switch(ilist->id) {
26+
case SASL_CB_USER:
27+
ilist->result = strdup(m_user_name);
28+
ilist->len = strlen((const char*)ilist->result);
29+
break;
30+
case SASL_CB_AUTHNAME:
31+
ilist->result = strdup(m_user_name);
32+
ilist->len = strlen((const char*)ilist->result);
33+
break;
34+
case SASL_CB_PASS:
35+
ilist->result = strdup(m_user_pwd);
36+
ilist->len = strlen((const char*)ilist->result);
37+
break;
38+
default:
39+
ilist->result = NULL;
40+
ilist->len = 0;
41+
}
42+
ilist++;
43+
}
44+
}
45+
46+
void Sasl_client::SetPluginInfo(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) {
47+
m_vio = vio;
48+
m_mysql = mysql;
49+
}
50+
51+
/*
52+
SASL method is send from the Mysql server, and this is set by the client.
53+
SASL client and sasl server may support many sasl authentication methods and can negotiate in anyone.
54+
We want to inforce the SASL authentication set by the client.
55+
*/
56+
int Sasl_client::ReadMethodNameFromServer() {
57+
int rc_server_read = CR_ERROR;
58+
unsigned char* packet = NULL;
59+
std::stringstream log_stream;
60+
61+
if(m_vio == NULL) {
62+
return rc_server_read;
63+
}
64+
// Get authentication method from the server
65+
rc_server_read = m_vio->read_packet(m_vio, (unsigned char**)&packet);
66+
strncpy(m_mechanism, (const char*)packet, sizeof(m_mechanism));
67+
log_stream << "Method name : " << m_mechanism;
68+
log_info(log_stream.str());
69+
return rc_server_read;
70+
}
71+
72+
Sasl_client::Sasl_client() {
73+
m_connection = NULL;
74+
}
75+
76+
int Sasl_client::Initilize() {
77+
int rc_sasl = SASL_FAIL;
78+
79+
strncpy(m_service_name, SASL_SERVICE_NAME, sizeof(m_service_name));
80+
81+
// Initialize client-side of SASL
82+
rc_sasl = sasl_client_init(NULL);
83+
if(rc_sasl != SASL_OK)
84+
goto EXIT;
85+
86+
// Creating sasl connection
87+
rc_sasl = sasl_client_new(m_service_name, NULL, NULL, NULL, callbacks,
88+
0, &m_connection);
89+
if(rc_sasl != SASL_OK)
90+
goto EXIT;
91+
92+
// Set security peoperties
93+
sasl_setprop(m_connection, SASL_SEC_PROPS, &security_properties);
94+
rc_sasl= SASL_OK;
95+
EXIT:
96+
return rc_sasl;
97+
}
98+
99+
int Sasl_client::UnInitilize() {
100+
int rc_sasl = SASL_FAIL;
101+
if (m_connection) {
102+
sasl_dispose(&m_connection);
103+
m_connection = NULL;
104+
sasl_client_done();
105+
}
106+
return rc_sasl;
107+
}
108+
109+
int Sasl_client::SendSaslRequestToServer(const unsigned char *request, int request_len, unsigned char** response, int* response_len) {
110+
int rc_server = CR_ERROR;
111+
std::stringstream log_stream;
112+
113+
if(m_vio == NULL) {
114+
goto EXIT;
115+
}
116+
// Send the request to the MySQL server
117+
log_stream << "Sasl_client::SendSaslRequestToServer request:" << request;
118+
log_info(log_stream.str());
119+
rc_server = m_vio->write_packet(m_vio, request, request_len);
120+
if(rc_server) {
121+
log_error("Sasl_client::SendSaslRequestToServer: sasl request write failed");
122+
goto EXIT;
123+
}
124+
125+
// Get the sasl reponse from the MySQL server
126+
*response_len = m_vio->read_packet(m_vio, response);
127+
if((*response_len) < 0 || (*response == NULL)) {
128+
log_error("Sasl_client::SendSaslRequestToServer: sasl reponse read failed");
129+
goto EXIT;
130+
}
131+
log_stream.str("");
132+
log_stream << "Sasl_client::SendSaslRequestToServer response:" << *response;
133+
EXIT:
134+
return rc_server;
135+
}
136+
137+
int Sasl_client::SaslStart(char **client_output, int* client_output_length) {
138+
int rc_sasl = SASL_FAIL;
139+
const char *mechanisum = NULL;
140+
char* sasl_client_output = NULL;
141+
sasl_interact_t *interactions = NULL;
142+
std::stringstream log_stream;
143+
144+
if(m_connection == NULL) {
145+
log_error("Sasl_client::SaslStart: sasl connection is null");
146+
return rc_sasl;
147+
}
148+
do {
149+
rc_sasl = sasl_client_start(m_connection, m_mechanism, &interactions,
150+
(const char**)&sasl_client_output, (unsigned int *)client_output_length,
151+
&mechanisum);
152+
153+
if(rc_sasl == SASL_INTERACT) Interact(interactions);
154+
}
155+
while(rc_sasl == SASL_INTERACT);
156+
157+
if(client_output != NULL) {
158+
*client_output = sasl_client_output;
159+
log_stream << "Sasl_client::SaslStart sasl output: " << sasl_client_output;
160+
log_info(log_stream.str());
161+
}
162+
return rc_sasl;
163+
}
164+
165+
int Sasl_client::SaslStep(char* server_in, int server_in_length, char** client_out, int* client_out_length)
166+
{
167+
int rc_sasl = SASL_FAIL;
168+
sasl_interact_t *interactions = NULL;
169+
170+
if(m_connection == NULL) {
171+
return rc_sasl;
172+
}
173+
do {
174+
rc_sasl = sasl_client_step(m_connection,
175+
server_in, server_in_length,
176+
&interactions,
177+
(const char**)client_out, (unsigned int *)client_out_length);
178+
if(rc_sasl == SASL_INTERACT) Sasl_client::Interact(interactions);
179+
}
180+
while(rc_sasl == SASL_INTERACT);
181+
182+
return rc_sasl;
183+
}
184+
185+
void Sasl_client::SetUserInfo(std::string name, std::string pwd) {
186+
strncpy(m_user_name, name.c_str(), sizeof(m_user_name));
187+
strncpy(m_user_pwd, pwd.c_str(), sizeof(m_user_pwd));
188+
}
189+
190+
static int sasl_authenticate(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) {
191+
int rc_sasl = SASL_FAIL;
192+
int rc_auth = CR_ERROR;
193+
unsigned char* server_packet = NULL;
194+
int server_packet_len = 0;
195+
char *sasl_client_output = NULL;
196+
int sasl_client_output_len = 0;
197+
std::stringstream log_stream;
198+
199+
Sasl_client sasl_client;
200+
sasl_client.SetUserInfo(mysql->user, mysql->passwd);
201+
sasl_client.SetPluginInfo(vio, mysql);
202+
server_packet_len = sasl_client.ReadMethodNameFromServer();
203+
if(server_packet_len < 0) {
204+
log_error("sasl_authenticate: method name read from server side plugin failed");
205+
goto EXIT;
206+
}
207+
208+
rc_sasl = sasl_client.Initilize();
209+
if(rc_sasl != SASL_OK) {
210+
log_error("sasl_authenticate: initilize failed");
211+
goto EXIT;
212+
}
213+
214+
rc_sasl = sasl_client.SaslStart(&sasl_client_output, &sasl_client_output_len);
215+
if((rc_sasl != SASL_OK) && (rc_sasl != SASL_CONTINUE)) {
216+
log_error("sasl_authenticate: SaslStart failed");
217+
goto EXIT;
218+
}
219+
220+
// Running SASL authentication step till authentication process is concluded
221+
// MySQL server plugin working as proxy for SASL / LDAP server.
222+
do {
223+
rc_auth = sasl_client.SendSaslRequestToServer((const unsigned char *)sasl_client_output,sasl_client_output_len,&server_packet,&server_packet_len);
224+
if(rc_auth < 0) {
225+
goto EXIT;
226+
}
227+
228+
server_packet_len = strlen((const char*)server_packet); // To be remove
229+
rc_sasl = sasl_client.SaslStep((char*)server_packet,server_packet_len,&sasl_client_output,&sasl_client_output_len);
230+
} while (rc_sasl == SASL_CONTINUE );
231+
232+
if(rc_sasl == SASL_OK) {
233+
rc_auth = CR_OK;
234+
log_info("sasl_authenticate authentication successful");
235+
}
236+
else {
237+
log_error("sasl_authenticate client failed");
238+
}
239+
240+
EXIT:
241+
rc_sasl = sasl_client.UnInitilize();
242+
return rc_auth;
243+
}
244+
245+
mysql_declare_client_plugin(AUTHENTICATION)
246+
"authentication_ldap_sasl_client",
247+
"Oracle",
248+
"LDAP SASL Client Authentication Plugin",
249+
{0,1,0},
250+
"PROPRIETARY",
251+
NULL,
252+
NULL,
253+
NULL,
254+
NULL,
255+
sasl_authenticate
256+
mysql_end_client_plugin;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
2+
3+
#ifndef AUTH_LDAP_SASL_CLIENT_H_
4+
#define AUTH_LDAP_SASL_CLIENT_H_
5+
6+
#include <string.h>
7+
#include <stdio.h>
8+
#include <stdlib.h>
9+
#include <sasl/sasl.h>
10+
#include <mysql/client_plugin.h>
11+
#include <mysql/plugin.h>
12+
#include <mysql/plugin_auth_common.h>
13+
#include <mysql.h>
14+
#include "log.h"
15+
16+
#define SASL_MAX_STR_SIZE 1024
17+
#define SASL_BUFFER_SIZE 9000
18+
#define SASL_SERVICE_NAME "ldap"
19+
20+
static const sasl_callback_t callbacks[] = {
21+
#ifdef SASL_CB_GETREALM
22+
{SASL_CB_GETREALM, NULL, NULL},
23+
#endif
24+
{SASL_CB_USER, NULL, NULL},
25+
{SASL_CB_AUTHNAME, NULL, NULL},
26+
{SASL_CB_PASS, NULL, NULL},
27+
{SASL_CB_ECHOPROMPT, NULL, NULL},
28+
{SASL_CB_NOECHOPROMPT, NULL, NULL},
29+
{SASL_CB_LIST_END, NULL, NULL}
30+
};
31+
32+
sasl_security_properties_t security_properties = {
33+
0,
34+
1,
35+
0,
36+
0,
37+
NULL,
38+
NULL,
39+
};
40+
41+
class Sasl_client {
42+
public:
43+
Sasl_client();
44+
int Initilize();
45+
int UnInitilize();
46+
void SetPluginInfo(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
47+
void Interact(sasl_interact_t *ilist);
48+
int ReadMethodNameFromServer();
49+
int SaslStart(char **client_output, int* client_output_length);
50+
int SaslStep(char* server_in, int server_in_length, char** client_out, int* client_out_length);
51+
int SendSaslRequestToServer(const unsigned char *request, int request_len, unsigned char** reponse, int* response_len);
52+
void SetUserInfo(std::string name, std::string pwd);
53+
protected:
54+
char m_user_name[SASL_MAX_STR_SIZE];
55+
char m_user_pwd[SASL_MAX_STR_SIZE];
56+
char m_mechanism[SASL_MAX_STR_SIZE];
57+
char m_service_name[SASL_MAX_STR_SIZE];
58+
sasl_conn_t *m_connection;
59+
MYSQL_PLUGIN_VIO *m_vio;
60+
MYSQL *m_mysql;
61+
};
62+
63+
#endif //AUTH_LDAP_SASL_CLIENT_H_

0 commit comments

Comments
 (0)