blob: 55e8558a5272cb0447ad9268ad9c7f27e2f30385 [file] [log] [blame]
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License
#include <process/authenticator.hpp>
#include <string>
#include <vector>
#include <process/dispatch.hpp>
#include <process/future.hpp>
#include <process/http.hpp>
#include <process/process.hpp>
#include <stout/base64.hpp>
#include <stout/hashmap.hpp>
#include <stout/option.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>
namespace process {
namespace http {
namespace authentication {
using std::string;
using std::vector;
class BasicAuthenticatorProcess : public Process<BasicAuthenticatorProcess>
{
public:
BasicAuthenticatorProcess(
const string& realm,
const hashmap<string, string>& credentials);
virtual Future<AuthenticationResult> authenticate(
const http::Request& request);
private:
const string realm_;
const hashmap<string, string> credentials_;
};
BasicAuthenticatorProcess::BasicAuthenticatorProcess(
const string& realm,
const hashmap<string, string>& credentials)
: realm_(realm), credentials_(credentials) {}
Future<AuthenticationResult> BasicAuthenticatorProcess::authenticate(
const Request& request)
{
AuthenticationResult unauthorized;
unauthorized.unauthorized =
Unauthorized({"Basic realm=\"" + realm_ + "\""});
Option<string> credentials = request.headers.get("Authorization");
if (credentials.isNone()) {
return unauthorized;
}
vector<string> components = strings::split(credentials.get(), " ");
if (components.size() != 2 || components[0] != "Basic") {
return unauthorized;
}
Try<string> decoded = base64::decode(components[1]);
if (decoded.isError()) {
return unauthorized;
}
vector<string> credential = strings::split(decoded.get(), ":");
if (credential.size() != 2 ||
!credentials_.contains(credential[0]) ||
credentials_.at(credential[0]) != credential[1]) {
return unauthorized;
}
AuthenticationResult authenticated;
authenticated.principal = credential[0];
return authenticated;
}
BasicAuthenticator::BasicAuthenticator(
const string& realm,
const hashmap<string, string>& credentials)
: process_(new BasicAuthenticatorProcess(realm, credentials))
{
spawn(*process_);
}
BasicAuthenticator::~BasicAuthenticator()
{
terminate(*process_);
wait(*process_);
}
Future<AuthenticationResult> BasicAuthenticator::authenticate(
const Request& request)
{
return dispatch(*process_, &BasicAuthenticatorProcess::authenticate, request);
}
string BasicAuthenticator::scheme() const
{
return "Basic";
}
} // namespace authentication {
} // namespace http {
} // namespace process {