summaryrefslogtreecommitdiffstats
path: root/src/auth/Auth.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/auth/Auth.h')
-rw-r--r--src/auth/Auth.h319
1 files changed, 319 insertions, 0 deletions
diff --git a/src/auth/Auth.h b/src/auth/Auth.h
new file mode 100644
index 000000000..5521c8d3f
--- /dev/null
+++ b/src/auth/Auth.h
@@ -0,0 +1,319 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#ifndef CEPH_AUTHTYPES_H
+#define CEPH_AUTHTYPES_H
+
+#include "Crypto.h"
+#include "common/entity_name.h"
+
+// The _MAX values are a bit wonky here because we are overloading the first
+// byte of the auth payload to identify both the type of authentication to be
+// used *and* the encoding version for the authenticator. So, we define a
+// range.
+enum {
+ AUTH_MODE_NONE = 0,
+ AUTH_MODE_AUTHORIZER = 1,
+ AUTH_MODE_AUTHORIZER_MAX = 9,
+ AUTH_MODE_MON = 10,
+ AUTH_MODE_MON_MAX = 19,
+};
+
+
+struct EntityAuth {
+ CryptoKey key;
+ std::map<std::string, ceph::buffer::list> caps;
+ CryptoKey pending_key; ///< new but uncommitted key
+
+ void encode(ceph::buffer::list& bl) const {
+ __u8 struct_v = 3;
+ using ceph::encode;
+ encode(struct_v, bl);
+ encode((uint64_t)CEPH_AUTH_UID_DEFAULT, bl);
+ encode(key, bl);
+ encode(caps, bl);
+ encode(pending_key, bl);
+ }
+ void decode(ceph::buffer::list::const_iterator& bl) {
+ using ceph::decode;
+ __u8 struct_v;
+ decode(struct_v, bl);
+ if (struct_v >= 2) {
+ uint64_t old_auid;
+ decode(old_auid, bl);
+ }
+ decode(key, bl);
+ decode(caps, bl);
+ if (struct_v >= 3) {
+ decode(pending_key, bl);
+ }
+ }
+};
+WRITE_CLASS_ENCODER(EntityAuth)
+
+inline std::ostream& operator<<(std::ostream& out, const EntityAuth& a)
+{
+ out << "auth(key=" << a.key;
+ if (!a.pending_key.empty()) {
+ out << " pending_key=" << a.pending_key;
+ }
+ out << ")";
+ return out;
+}
+
+struct AuthCapsInfo {
+ bool allow_all;
+ ceph::buffer::list caps;
+
+ AuthCapsInfo() : allow_all(false) {}
+
+ void encode(ceph::buffer::list& bl) const {
+ using ceph::encode;
+ __u8 struct_v = 1;
+ encode(struct_v, bl);
+ __u8 a = (__u8)allow_all;
+ encode(a, bl);
+ encode(caps, bl);
+ }
+ void decode(ceph::buffer::list::const_iterator& bl) {
+ using ceph::decode;
+ __u8 struct_v;
+ decode(struct_v, bl);
+ __u8 a;
+ decode(a, bl);
+ allow_all = (bool)a;
+ decode(caps, bl);
+ }
+};
+WRITE_CLASS_ENCODER(AuthCapsInfo)
+
+/*
+ * The ticket (if properly validated) authorizes the principal use
+ * services as described by 'caps' during the specified validity
+ * period.
+ */
+struct AuthTicket {
+ EntityName name;
+ uint64_t global_id; /* global instance id */
+ utime_t created, renew_after, expires;
+ AuthCapsInfo caps;
+ __u32 flags;
+
+ AuthTicket() : global_id(0), flags(0){}
+
+ void init_timestamps(utime_t now, double ttl) {
+ created = now;
+ expires = now;
+ expires += ttl;
+ renew_after = now;
+ renew_after += ttl / 2.0;
+ }
+
+ void encode(ceph::buffer::list& bl) const {
+ using ceph::encode;
+ __u8 struct_v = 2;
+ encode(struct_v, bl);
+ encode(name, bl);
+ encode(global_id, bl);
+ encode((uint64_t)CEPH_AUTH_UID_DEFAULT, bl);
+ encode(created, bl);
+ encode(expires, bl);
+ encode(caps, bl);
+ encode(flags, bl);
+ }
+ void decode(ceph::buffer::list::const_iterator& bl) {
+ using ceph::decode;
+ __u8 struct_v;
+ decode(struct_v, bl);
+ decode(name, bl);
+ decode(global_id, bl);
+ if (struct_v >= 2) {
+ uint64_t old_auid;
+ decode(old_auid, bl);
+ }
+ decode(created, bl);
+ decode(expires, bl);
+ decode(caps, bl);
+ decode(flags, bl);
+ }
+};
+WRITE_CLASS_ENCODER(AuthTicket)
+
+
+/*
+ * abstract authorizer class
+ */
+struct AuthAuthorizer {
+ __u32 protocol;
+ ceph::buffer::list bl;
+ CryptoKey session_key;
+
+ explicit AuthAuthorizer(__u32 p) : protocol(p) {}
+ virtual ~AuthAuthorizer() {}
+ virtual bool verify_reply(ceph::buffer::list::const_iterator& reply,
+ std::string *connection_secret) = 0;
+ virtual bool add_challenge(CephContext *cct,
+ const ceph::buffer::list& challenge) = 0;
+};
+
+struct AuthAuthorizerChallenge {
+ virtual ~AuthAuthorizerChallenge() {}
+};
+
+struct AuthConnectionMeta {
+ uint32_t auth_method = CEPH_AUTH_UNKNOWN; //< CEPH_AUTH_*
+
+ /// client: initial empty, but populated if server said bad method
+ std::vector<uint32_t> allowed_methods;
+
+ int auth_mode = AUTH_MODE_NONE; ///< AUTH_MODE_*
+
+ int con_mode = 0; ///< negotiated mode
+
+ bool is_mode_crc() const {
+ return con_mode == CEPH_CON_MODE_CRC;
+ }
+ bool is_mode_secure() const {
+ return con_mode == CEPH_CON_MODE_SECURE;
+ }
+
+ CryptoKey session_key; ///< per-ticket key
+
+ size_t get_connection_secret_length() const {
+ switch (con_mode) {
+ case CEPH_CON_MODE_CRC:
+ return 0;
+ case CEPH_CON_MODE_SECURE:
+ return 16 * 4;
+ }
+ return 0;
+ }
+ std::string connection_secret; ///< per-connection key
+
+ std::unique_ptr<AuthAuthorizer> authorizer;
+ std::unique_ptr<AuthAuthorizerChallenge> authorizer_challenge;
+
+ ///< set if msgr1 peer doesn't support CEPHX_V2
+ bool skip_authorizer_challenge = false;
+};
+
+/*
+ * Key management
+ */
+#define KEY_ROTATE_NUM 3 /* prev, current, next */
+
+struct ExpiringCryptoKey {
+ CryptoKey key;
+ utime_t expiration;
+
+ void encode(ceph::buffer::list& bl) const {
+ using ceph::encode;
+ __u8 struct_v = 1;
+ encode(struct_v, bl);
+ encode(key, bl);
+ encode(expiration, bl);
+ }
+ void decode(ceph::buffer::list::const_iterator& bl) {
+ using ceph::decode;
+ __u8 struct_v;
+ decode(struct_v, bl);
+ decode(key, bl);
+ decode(expiration, bl);
+ }
+};
+WRITE_CLASS_ENCODER(ExpiringCryptoKey)
+
+inline std::ostream& operator<<(std::ostream& out, const ExpiringCryptoKey& c)
+{
+ return out << c.key << " expires " << c.expiration;
+}
+
+struct RotatingSecrets {
+ std::map<uint64_t, ExpiringCryptoKey> secrets;
+ version_t max_ver;
+
+ RotatingSecrets() : max_ver(0) {}
+
+ void encode(ceph::buffer::list& bl) const {
+ using ceph::encode;
+ __u8 struct_v = 1;
+ encode(struct_v, bl);
+ encode(secrets, bl);
+ encode(max_ver, bl);
+ }
+ void decode(ceph::buffer::list::const_iterator& bl) {
+ using ceph::decode;
+ __u8 struct_v;
+ decode(struct_v, bl);
+ decode(secrets, bl);
+ decode(max_ver, bl);
+ }
+
+ uint64_t add(ExpiringCryptoKey& key) {
+ secrets[++max_ver] = key;
+ while (secrets.size() > KEY_ROTATE_NUM)
+ secrets.erase(secrets.begin());
+ return max_ver;
+ }
+
+ bool need_new_secrets() const {
+ return secrets.size() < KEY_ROTATE_NUM;
+ }
+ bool need_new_secrets(const utime_t& now) const {
+ return secrets.size() < KEY_ROTATE_NUM || current().expiration <= now;
+ }
+
+ ExpiringCryptoKey& previous() {
+ return secrets.begin()->second;
+ }
+ ExpiringCryptoKey& current() {
+ auto p = secrets.begin();
+ ++p;
+ return p->second;
+ }
+ const ExpiringCryptoKey& current() const {
+ auto p = secrets.begin();
+ ++p;
+ return p->second;
+ }
+ ExpiringCryptoKey& next() {
+ return secrets.rbegin()->second;
+ }
+ bool empty() {
+ return secrets.empty();
+ }
+
+ void dump();
+};
+WRITE_CLASS_ENCODER(RotatingSecrets)
+
+
+
+class KeyStore {
+public:
+ virtual ~KeyStore() {}
+ virtual bool get_secret(const EntityName& name, CryptoKey& secret) const = 0;
+ virtual bool get_service_secret(uint32_t service_id, uint64_t secret_id,
+ CryptoKey& secret) const = 0;
+};
+
+inline bool auth_principal_needs_rotating_keys(EntityName& name)
+{
+ uint32_t ty(name.get_type());
+ return ((ty == CEPH_ENTITY_TYPE_OSD)
+ || (ty == CEPH_ENTITY_TYPE_MDS)
+ || (ty == CEPH_ENTITY_TYPE_MGR));
+}
+
+#endif