Status CmdAuthenticate::_authenticateX509(const UserName& user, const BSONObj& cmdObj) { if (!getSSLManager()) { return Status(ErrorCodes::ProtocolError, "SSL support is required for the MONGODB-X509 mechanism."); } if(user.getDB() != "$external") { return Status(ErrorCodes::ProtocolError, "X.509 authentication must always use the $external database."); } ClientBasic *client = ClientBasic::getCurrent(); AuthorizationSession* authorizationSession = client->getAuthorizationSession(); std::string subjectName = client->port()->getX509SubjectName(); if (user.getUser() != subjectName) { return Status(ErrorCodes::AuthenticationFailed, "There is no x.509 client certificate matching the user."); } else { std::string srvSubjectName = getSSLManager()->getServerSubjectName(); size_t srvClusterIdPos = srvSubjectName.find(",OU="); size_t peerClusterIdPos = subjectName.find(",OU="); std::string srvClusterId = srvClusterIdPos != std::string::npos ? srvSubjectName.substr(srvClusterIdPos) : ""; std::string peerClusterId = peerClusterIdPos != std::string::npos ? subjectName.substr(peerClusterIdPos) : ""; // Handle internal cluster member auth, only applies to server-server connections int clusterAuthMode = serverGlobalParams.clusterAuthMode.load(); if (srvClusterId == peerClusterId && !srvClusterId.empty()) { if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_undefined || clusterAuthMode == ServerGlobalParams::ClusterAuthMode_keyFile) { return Status(ErrorCodes::AuthenticationFailed, "The provided certificate " "can only be used for cluster authentication, not client " "authentication. The current configuration does not allow " "x.509 cluster authentication, check the --clusterAuthMode flag"); } authorizationSession->grantInternalAuthorization(); } // Handle normal client authentication, only applies to client-server connections else { if (_isX509AuthDisabled) { return Status(ErrorCodes::BadValue, _x509AuthenticationDisabledMessage); } Status status = authorizationSession->addAndAuthorizeUser(user); if (!status.isOK()) { return status; } } return Status::OK(); } }
Status CmdAuthenticate::_authenticateX509( OperationContext* txn, const UserName& user, const BSONObj& cmdObj) { if (!getSSLManager()) { return Status(ErrorCodes::ProtocolError, "SSL support is required for the MONGODB-X509 mechanism."); } if(user.getDB() != "$external") { return Status(ErrorCodes::ProtocolError, "X.509 authentication must always use the $external database."); } ClientBasic *client = ClientBasic::getCurrent(); AuthorizationSession* authorizationSession = AuthorizationSession::get(client); std::string subjectName = client->port()->getX509SubjectName(); if (!getSSLManager()->getSSLConfiguration().hasCA) { return Status(ErrorCodes::AuthenticationFailed, "Unable to verify x.509 certificate, as no CA has been provided."); } else if (user.getUser() != subjectName) { return Status(ErrorCodes::AuthenticationFailed, "There is no x.509 client certificate matching the user."); } else { std::string srvSubjectName = getSSLManager()->getSSLConfiguration().serverSubjectName; // Handle internal cluster member auth, only applies to server-server connections if (_clusterIdMatch(subjectName, srvSubjectName)) { int clusterAuthMode = serverGlobalParams.clusterAuthMode.load(); if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_undefined || clusterAuthMode == ServerGlobalParams::ClusterAuthMode_keyFile) { return Status(ErrorCodes::AuthenticationFailed, "The provided certificate " "can only be used for cluster authentication, not client " "authentication. The current configuration does not allow " "x.509 cluster authentication, check the --clusterAuthMode flag"); } authorizationSession->grantInternalAuthorization(); } // Handle normal client authentication, only applies to client-server connections else { if (_isX509AuthDisabled) { return Status(ErrorCodes::BadValue, _x509AuthenticationDisabledMessage); } Status status = authorizationSession->addAndAuthorizeUser(txn, user); if (!status.isOK()) { return status; } } return Status::OK(); } }
Status CmdAuthenticate::_authenticateCR(const UserName& user, const BSONObj& cmdObj) { if (user == internalSecurity.user->getName() && serverGlobalParams.clusterAuthMode == "x509") { return Status(ErrorCodes::AuthenticationFailed, "Mechanism x509 is required for internal cluster authentication"); } if (!_areNonceAuthenticateCommandsEnabled) { // SERVER-8461, MONGODB-CR must be enabled for authenticating the internal user, so that // cluster members may communicate with each other. if (user != internalSecurity.user->getName()) { return Status(ErrorCodes::BadValue, _nonceAuthenticateCommandsDisabledMessage); } } string key = cmdObj.getStringField("key"); string received_nonce = cmdObj.getStringField("nonce"); if( user.getUser().empty() || key.empty() || received_nonce.empty() ) { sleepmillis(10); return Status(ErrorCodes::ProtocolError, "field missing/wrong type in received authenticate command"); } stringstream digestBuilder; { ClientBasic *client = ClientBasic::getCurrent(); boost::scoped_ptr<AuthenticationSession> session; client->swapAuthenticationSession(session); if (!session || session->getType() != AuthenticationSession::SESSION_TYPE_MONGO) { sleepmillis(30); return Status(ErrorCodes::ProtocolError, "No pending nonce"); } else { nonce64 nonce = static_cast<MongoAuthenticationSession*>(session.get())->getNonce(); digestBuilder << hex << nonce; if (digestBuilder.str() != received_nonce) { sleepmillis(30); return Status(ErrorCodes::AuthenticationFailed, "Received wrong nonce."); } } } User* userObj; Status status = getGlobalAuthorizationManager()->acquireUser(user, &userObj); if (!status.isOK()) { // Failure to find the privilege document indicates no-such-user, a fact that we do not // wish to reveal to the client. So, we return AuthenticationFailed rather than passing // through the returned status. return Status(ErrorCodes::AuthenticationFailed, status.toString()); } string pwd = userObj->getCredentials().password; getGlobalAuthorizationManager()->releaseUser(userObj); md5digest d; { digestBuilder << user.getUser() << pwd; string done = digestBuilder.str(); md5_state_t st; md5_init(&st); md5_append(&st, (const md5_byte_t *) done.c_str(), done.size()); md5_finish(&st, d); } string computed = digestToString( d ); if ( key != computed ) { return Status(ErrorCodes::AuthenticationFailed, "key mismatch"); } AuthorizationSession* authorizationSession = ClientBasic::getCurrent()->getAuthorizationSession(); status = authorizationSession->addAndAuthorizeUser(user); if (!status.isOK()) { return status; } return Status::OK(); }
bool DbWebServer::_allowed(OperationContext* txn, const char* rq, vector<string>& headers, const SockAddr& from) { AuthorizationSession* authSess = AuthorizationSession::get(txn->getClient()); if (!authSess->getAuthorizationManager().isAuthEnabled()) { return true; } if (from.isLocalHost() && !_webUsers->haveAdminUsers(txn)) { authSess->grantInternalAuthorization(); return true; } string auth = getHeader(rq, "Authorization"); if (auth.size() > 0 && auth.find("Digest ") == 0) { auth = auth.substr(7) + ", "; map<string, string> parms; pcrecpp::StringPiece input(auth); string name, val; pcrecpp::RE re("(\\w+)=\"?(.*?)\"?,\\s*"); while (re.Consume(&input, &name, &val)) { parms[name] = val; } // Only users in the admin DB are visible by the webserver UserName userName(parms["username"], "admin"); User* user; AuthorizationManager& authzManager = authSess->getAuthorizationManager(); Status status = authzManager.acquireUser(txn, userName, &user); if (!status.isOK()) { if (status.code() != ErrorCodes::UserNotFound) { uasserted(17051, status.reason()); } } else { uassert( 17090, "External users don't have a password", !user->getCredentials().isExternal); string ha1 = user->getCredentials().password; authzManager.releaseUser(user); if (ha1.empty()) { return false; } const string ha2 = md5simpledigest((string) "GET" + ":" + parms["uri"]); stringstream r; r << ha1 << ':' << parms["nonce"]; if (parms["nc"].size() && parms["cnonce"].size() && parms["qop"].size()) { r << ':'; r << parms["nc"]; r << ':'; r << parms["cnonce"]; r << ':'; r << parms["qop"]; } r << ':'; r << ha2; const string r1 = md5simpledigest(r.str()); if (r1 == parms["response"]) { Status status = authSess->addAndAuthorizeUser(txn, userName); uassertStatusOK(status); return true; } } } stringstream authHeader; authHeader << "WWW-Authenticate: " << "Digest realm=\"mongo\", " << "nonce=\"abc\", " << "algorithm=MD5, qop=\"auth\" "; headers.push_back(authHeader.str()); return 0; }