12196819d70c9b1c8603c417f7f0ac9e423d4824
[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          * Returns all of the effective names for the Attribute.
120          *
121          * @return mutable array of identifiers, with the primary ID in the first position
122          */
123         std::vector<std::string>& getAliases() {
124             return m_id;
125         }
126
127         /**
128          * Sets whether case sensitivity should apply to basic value comparisons.
129          *
130          * @param caseSensitive  true iff value comparisons should be case sensitive
131          */
132         void setCaseSensitive(bool caseSensitive) {
133             m_caseSensitive = caseSensitive;
134         }
135
136         /**
137          * Indicates whether case sensitivity should apply to basic value comparisons.
138          *
139          * @return  true iff value comparisons should be case sensitive
140          */
141         bool isCaseSensitive() const {
142             return m_caseSensitive;
143         }
144         
145         /**
146          * Returns the number of values.
147          * 
148          * @return  number of values
149          */
150         virtual size_t valueCount() const {
151             return m_serialized.size();
152         }
153         
154         /**
155          * Returns serialized Attribute values encoded as UTF-8 strings.
156          * 
157          * @return  an immutable vector of values
158          */
159         virtual const std::vector<std::string>& getSerializedValues() const {
160             return m_serialized;
161         }
162         
163         /**
164          * Informs the Attribute that values have changed and any serializations
165          * must be cleared. 
166          */
167         virtual void clearSerializedValues()=0;
168         
169         /**
170          * Gets the string equivalent of the value at the specified position (starting from zero).
171          *
172          * @param index position of value
173          * @return the specified value in its "string" form, or NULL if undefined
174          */
175         virtual const char* getString(size_t index) const {
176             return m_serialized[index].c_str();
177         }
178
179         /**
180          * Gets the "scope" of the value at the specified position (starting from zero).
181          *
182          * @param index position of value
183          * @return the specified value's "scope", or NULL if attribute is unscoped
184          */
185         virtual const char* getScope(size_t index) const {
186             return NULL;
187         }
188
189         /**
190          * Removes the value at the specified position (starting from zero).
191          *
192          * @param index position of value to remove
193          */
194         virtual void removeValue(size_t index) {
195             if (index < m_serialized.size())
196                 m_serialized.erase(m_serialized.begin() + index);
197         }
198
199         /**
200          * Marshalls an Attribute for remoting.
201          * 
202          * <p>This allows Attribute objects to be communicated across process boundaries
203          * without excess XML parsing. The DDF returned must be a struct containing
204          * a single list member named with the Attribute's "id". The name of the struct
205          * should contain the registered name of the Attribute implementation.
206          */
207         virtual DDF marshall() const {
208             DDF ddf(NULL);
209             ddf.structure().addmember(m_id.front().c_str()).list();
210             if (!m_caseSensitive)
211                 ddf.addmember("case_insensitive");
212             if (m_id.size() > 1) {
213                 DDF alias;
214                 DDF aliases = ddf.addmember("aliases").list();
215                 for (std::vector<std::string>::const_iterator a = m_id.begin() + 1; a != m_id.end(); ++a) {
216                     alias = DDF(NULL).string(a->c_str());
217                     aliases.add(alias);
218                 }
219             }
220             return ddf;
221         }
222         
223         /**
224          * Unmarshalls a remoted Attribute.
225          * 
226          * @param in    remoted Attribute data
227          * @return  a resolved Attribute of the proper subclass 
228          */
229         static Attribute* unmarshall(DDF& in);
230         
231         /** A function that unmarshalls remoted data into the proper Attribute subclass. */
232         typedef Attribute* AttributeFactory(DDF& in);
233
234         /**
235          * Registers an AttributeFactory function for a given attribute "type".
236          * 
237          * @param type      string used at the root of remoted Attribute structures
238          * @param factory   factory function
239          */        
240         static void registerFactory(const char* type, AttributeFactory* factory) {
241             m_factoryMap[type] = factory;
242         }
243
244         /**
245          * Deregisters an AttributeFactory function for a given attribute "type".
246          * 
247          * @param type      string used at the root of remoted Attribute structures
248          */        
249         static void deregisterFactory(const char* type) {
250             m_factoryMap.erase(type);
251         }
252
253         /**
254          * Clears the map of factories.
255          */
256         static void deregisterFactories() {
257             m_factoryMap.clear();
258         }
259         
260     private:
261         static std::map<std::string,AttributeFactory*> m_factoryMap;
262         std::vector<std::string> m_id;
263         bool m_caseSensitive;
264     };
265
266 #if defined (_MSC_VER)
267     #pragma warning( pop )
268 #endif
269
270     /** Registers built-in Attribute types into the runtime. */
271     void registerAttributeFactories();
272     
273 };
274
275 #endif /* __shibsp_attribute_h__ */