Add back alias support for attributes.
[shibboleth/sp.git] / shibsp / attribute / Attribute.h
1 /*
2  *  Copyright 2001-2007 Internet2
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * @file shibsp/attribute/Attribute.h
19  * 
20  * A resolved attribute.
21  */
22
23 #ifndef __shibsp_attribute_h__
24 #define __shibsp_attribute_h__
25
26 #include <shibsp/exceptions.h>
27 #include <shibsp/remoting/ddf.h>
28
29 #include <map>
30 #include <string>
31 #include <vector>
32
33 namespace shibsp {
34
35 #if defined (_MSC_VER)
36     #pragma warning( push )
37     #pragma warning( disable : 4251 )
38 #endif
39
40     /**
41      * A resolved attribute.
42      * 
43      * <p>Resolved attributes are a neutral construct that represent both simple and
44      * complex attribute data structures that might be found in SAML assertions
45      * or obtained from other sources.
46      * 
47      * <p>Attributes consist of an id/name that is locally unique (that is, unique to a
48      * configuration at any given point in time) and zero or more values. Values can
49      * be of any type or structure, but will generally be made available to applications
50      * only if a serialized string form exists. More complex values can be used with
51      * access control plugins that understand them, however. 
52      */
53     class SHIBSP_API Attribute
54     {
55         MAKE_NONCOPYABLE(Attribute);
56     protected:
57         /**
58          * Constructor
59          * 
60          * @param ids   array with primary identifier in first position, followed by any aliases
61          */
62         Attribute(const std::vector<std::string>& ids) : m_id(ids), m_caseSensitive(true) {
63         }
64
65         /**
66          * Constructs based on a remoted Attribute.
67          * 
68          * <p>This allows Attribute objects to be recreated after marshalling.
69          * The DDF supplied must be a struct containing a single list member named
70          * with the Attribute's "id" and containing the values.
71          * 
72          * @param in    input object containing marshalled Attribute
73          */
74         Attribute(DDF& in) : m_caseSensitive(in["case_insensitive"].isnull()) {
75             const char* id = in.first().name();
76             if (id && *id)
77                 m_id.push_back(id);
78             else
79                 throw AttributeException("No id found in marshalled attribute content.");
80             DDF aliases = in["aliases"];
81             if (aliases.islist()) {
82                 DDF alias = aliases.first();
83                 while (alias.isstring()) {
84                     m_id.push_back(alias.string());
85                     alias = aliases.next();
86                 }
87             }
88         }
89         
90         /**
91          * Maintains a copy of serialized attribute values, when possible.
92          * 
93          * <p>Implementations should maintain the array when values are added or removed.
94          */
95         mutable std::vector<std::string> m_serialized;
96
97     public:
98         virtual ~Attribute() {}
99         
100         /**
101          * Returns the Attribute identifier.
102          * 
103          * @return the Attribute identifier
104          */
105         const char* getId() const {
106             return m_id.front().c_str();
107         }
108
109         /**
110          * Returns all of the effective names for the Attribute.
111          *
112          * @return immutable array of identifiers, with the primary ID in the first position
113          */
114         const std::vector<std::string>& getAliases() const {
115             return m_id;
116         }
117
118         /**
119          * Sets whether case sensitivity should apply to basic value comparisons.
120          *
121          * @param caseSensitive  true iff value comparisons should be case sensitive
122          */
123         void setCaseSensitive(bool caseSensitive) {
124             m_caseSensitive = caseSensitive;
125         }
126
127         /**
128          * Indicates whether case sensitivity should apply to basic value comparisons.
129          *
130          * @return  true iff value comparisons should be case sensitive
131          */
132         bool isCaseSensitive() const {
133             return m_caseSensitive;
134         }
135         
136         /**
137          * Returns the number of values.
138          * 
139          * @return  number of values
140          */
141         virtual size_t valueCount() const {
142             return m_serialized.size();
143         }
144         
145         /**
146          * Returns serialized Attribute values encoded as UTF-8 strings.
147          * 
148          * @return  an immutable vector of values
149          */
150         virtual const std::vector<std::string>& getSerializedValues() const {
151             return m_serialized;
152         }
153         
154         /**
155          * Informs the Attribute that values have changed and any serializations
156          * must be cleared. 
157          */
158         virtual void clearSerializedValues()=0;
159         
160         /**
161          * Gets the string equivalent of the value at the specified position (starting from zero).
162          *
163          * @param index position of value
164          * @return the specified value in its "string" form, or NULL if undefined
165          */
166         virtual const char* getString(size_t index) const {
167             return m_serialized[index].c_str();
168         }
169
170         /**
171          * Gets the "scope" of the value at the specified position (starting from zero).
172          *
173          * @param index position of value
174          * @return the specified value's "scope", or NULL if attribute is unscoped
175          */
176         virtual const char* getScope(size_t index) const {
177             return NULL;
178         }
179
180         /**
181          * Removes the value at the specified position (starting from zero).
182          *
183          * @param index position of value to remove
184          */
185         virtual void removeValue(size_t index) {
186             if (index < m_serialized.size())
187                 m_serialized.erase(m_serialized.begin() + index);
188         }
189
190         /**
191          * Marshalls an Attribute for remoting.
192          * 
193          * <p>This allows Attribute objects to be communicated across process boundaries
194          * without excess XML parsing. The DDF returned must be a struct containing
195          * a single list member named with the Attribute's "id". The name of the struct
196          * should contain the registered name of the Attribute implementation.
197          */
198         virtual DDF marshall() const {
199             DDF ddf(NULL);
200             ddf.structure().addmember(m_id.front().c_str()).list();
201             if (!m_caseSensitive)
202                 ddf.addmember("case_insensitive");
203             if (m_id.size() > 1) {
204                 DDF alias;
205                 DDF aliases = ddf.addmember("aliases").list();
206                 for (std::vector<std::string>::const_iterator a = m_id.begin() + 1; a != m_id.end(); ++a) {
207                     alias = DDF(NULL).string(a->c_str());
208                     aliases.add(alias);
209                 }
210             }
211             return ddf;
212         }
213         
214         /**
215          * Unmarshalls a remoted Attribute.
216          * 
217          * @param in    remoted Attribute data
218          * @return  a resolved Attribute of the proper subclass 
219          */
220         static Attribute* unmarshall(DDF& in);
221         
222         /** A function that unmarshalls remoted data into the proper Attribute subclass. */
223         typedef Attribute* AttributeFactory(DDF& in);
224
225         /**
226          * Registers an AttributeFactory function for a given attribute "type".
227          * 
228          * @param type      string used at the root of remoted Attribute structures
229          * @param factory   factory function
230          */        
231         static void registerFactory(const char* type, AttributeFactory* factory) {
232             m_factoryMap[type] = factory;
233         }
234
235         /**
236          * Deregisters an AttributeFactory function for a given attribute "type".
237          * 
238          * @param type      string used at the root of remoted Attribute structures
239          */        
240         static void deregisterFactory(const char* type) {
241             m_factoryMap.erase(type);
242         }
243
244         /**
245          * Clears the map of factories.
246          */
247         static void deregisterFactories() {
248             m_factoryMap.clear();
249         }
250         
251     private:
252         static std::map<std::string,AttributeFactory*> m_factoryMap;
253         std::vector<std::string> m_id;
254         bool m_caseSensitive;
255     };
256
257 #if defined (_MSC_VER)
258     #pragma warning( pop )
259 #endif
260
261     /** Registers built-in Attribute types into the runtime. */
262     void registerAttributeFactories();
263     
264 };
265
266 #endif /* __shibsp_attribute_h__ */