Complete.
[metaproxy-moved-to-github.git] / src / filter_auth_simple.cpp
1 /* $Id: filter_auth_simple.cpp,v 1.3 2006-01-16 16:32:33 mike Exp $
2    Copyright (c) 2005, Index Data.
3
4 %LICENSE%
5  */
6
7 #include "config.hpp"
8
9 #include "filter.hpp"
10 #include "package.hpp"
11
12 #include <boost/thread/mutex.hpp>
13
14 #include "util.hpp"
15 #include "filter_auth_simple.hpp"
16
17 #include <yaz/zgdu.h>
18 #include <stdio.h>
19 #include <errno.h>
20
21 namespace yf = yp2::filter;
22
23 namespace yp2 {
24     namespace filter {
25         class AuthSimple::Rep {
26             friend class AuthSimple;
27             typedef std::map<std::string, std::string> userpass;
28             userpass reg;
29         };
30     }
31 }
32
33 yf::AuthSimple::AuthSimple() : m_p(new Rep)
34 {
35     // nothing to do
36 }
37
38 yf::AuthSimple::~AuthSimple()
39 {  // must have a destructor because of boost::scoped_ptr
40 }
41
42
43 void reject(yp2::Package &package, const char *addinfo) {
44     // Make an Init rejection APDU
45     Z_GDU *gdu = package.request().get();
46     yp2::odr odr;
47     Z_APDU *apdu = odr.create_initResponse(gdu->u.z3950, 1014, addinfo);
48     apdu->u.initResponse->implementationName = "YP2/YAZ";
49     *apdu->u.initResponse->result = 0; // reject
50     package.response() = apdu;
51     package.session().close();
52 }
53
54
55 void yf::AuthSimple::process(yp2::Package &package) const
56 {
57     Z_GDU *gdu = package.request().get();
58
59     if (!gdu || gdu->which != Z_GDU_Z3950 ||
60         gdu->u.z3950->which != Z_APDU_initRequest) {
61         // pass on package -- I think that means authentication is
62         // accepted which may not be the correct thing for non-Z APDUs
63         // as it means that SRW sessions don't demand authentication
64         return package.move();
65     }
66
67     Z_IdAuthentication *auth = gdu->u.z3950->u.initRequest->idAuthentication;
68     if (!auth)
69         return reject(package, "no credentials supplied");
70     if (auth->which != Z_IdAuthentication_idPass)
71         return reject(package, "only idPass authentication is supported");
72     Z_IdPass *idPass = auth->u.idPass;
73     // groupId is ignored, in accordance with ancient tradition
74     if (m_p->reg[idPass->userId] == idPass->password) {
75         // Success!   Should the authentication information now be
76         // altered or deleted?  That could be configurable.
77         return package.move();
78     }
79     return reject(package, "username/password combination rejected");
80 }
81
82
83 // Read XML config.. Put config info in m_p.
84 void yp2::filter::AuthSimple::configure(const xmlNode * ptr)
85 {
86     std::string filename;
87     bool got_filename = false;
88
89     for (ptr = ptr->children; ptr != 0; ptr = ptr->next) {
90         if (ptr->type != XML_ELEMENT_NODE)
91             continue;
92         if (!strcmp((const char *) ptr->name, "filename")) {
93             filename = yp2::xml::get_text(ptr);
94             got_filename = true;
95         } else {
96             throw yp2::filter::FilterException("Bad element in auth_simple: " 
97                                                + std::string((const char *)
98                                                              ptr->name));
99         }
100     }
101
102     if (!got_filename)
103         throw yp2::filter::FilterException("auth_simple: no user-register "
104                                            "filename specified");
105
106     FILE *fp = fopen(filename.c_str(), "r");
107     if (fp == 0)
108         throw yp2::filter::FilterException("can't open auth_simple " 
109                                            "user-register '" + filename +
110                                            "': " + strerror(errno));
111
112     char buf[1000];
113     while (fgets(buf, sizeof buf, fp)) {
114         if (*buf == '\n' || *buf == '#')
115             continue;
116         buf[strlen(buf)-1] = 0;
117         char *cp = strchr(buf, ':');
118         if (cp == 0)
119             throw yp2::filter::FilterException("auth_simple user-register '" +
120                                                filename + "': bad line: " +
121                                                buf);
122         *cp++ = 0;
123         m_p->reg[buf] = cp;
124         //printf("Added user '%s' -> password '%s'\n", buf, cp);
125     }
126 }
127
128 static yp2::filter::Base* filter_creator()
129 {
130     return new yp2::filter::AuthSimple;
131 }
132
133 extern "C" {
134     struct yp2_filter_struct yp2_filter_auth_simple = {
135         0,
136         "auth_simple",
137         filter_creator
138     };
139 }
140
141
142 /*
143  * Local variables:
144  * c-basic-offset: 4
145  * indent-tabs-mode: nil
146  * c-file-style: "stroustrup"
147  * End:
148  * vim: shiftwidth=4 tabstop=8 expandtab
149  */