Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
BasicDomain |
|
| 3.473684210526316;3.474 | ||||
BasicDomain$1 |
|
| 3.473684210526316;3.474 | ||||
BasicDomain$2 |
|
| 3.473684210526316;3.474 | ||||
BasicDomain$3 |
|
| 3.473684210526316;3.474 | ||||
BasicDomain$PathMatcher |
|
| 3.473684210526316;3.474 |
1 | /* | |
2 | * Copyright (c) 2009, Swiss Federal Department of Defence Civil Protection and Sport | |
3 | * (http://www.vbs.admin.ch) | |
4 | * Copyright (c) 2009, Ergon Informatik AG (http://www.ergon.ch) | |
5 | * All rights reserved. | |
6 | * | |
7 | * Licensed under the Open Permis License which accompanies this distribution, | |
8 | * and is available at http://www.openpermis.org/BSDlicenceKent.txt | |
9 | */ | |
10 | package org.openpermis.policy.bean.basic; | |
11 | ||
12 | import java.net.URI; | |
13 | ||
14 | import javax.naming.NamingException; | |
15 | import javax.naming.ldap.LdapName; | |
16 | ||
17 | import org.openpermis.policy.Domain; | |
18 | import org.openpermis.policy.bean.DomainBean; | |
19 | import org.openpermis.policy.bean.SerialNumber; | |
20 | ||
21 | /** | |
22 | * A basic implementation of {@link Domain}. | |
23 | * @since 0.1.0 | |
24 | */ | |
25 | public class BasicDomain | |
26 | extends BasicPartBean | |
27 | implements DomainBean | |
28 | { | |
29 | ||
30 | //---- Static | |
31 | ||
32 | /** | |
33 | * Determines if a path is contained within a domain path. | |
34 | * @since 0.3.0 | |
35 | */ | |
36 | public static interface PathMatcher { | |
37 | /** | |
38 | * Returns whether a domain contains a resource. | |
39 | * @param domainPath the path for the domain. | |
40 | * @param resourcePath the path for the resource. | |
41 | * @return <code>true</code> if this matcher considers the resource to part of the domain. | |
42 | * @since 0.3.0 | |
43 | */ | |
44 | boolean contains (String domainPath, String resourcePath); | |
45 | } | |
46 | ||
47 | /** | |
48 | * A path matcher where a domain contains a resource if the path of the resource starts | |
49 | * with the path of the domain. | |
50 | * <p>This matcher fits paths in a file system or a HTTP URL. | |
51 | * @since 0.3.0 | |
52 | */ | |
53 | 1 | protected static final PathMatcher DIRECTORY_PATH_MATCHER = |
54 | new PathMatcher() { | |
55 | 1 | public boolean contains (String domainPath, String resourcePath) { |
56 | 15 | return resourcePath.startsWith(domainPath); |
57 | } | |
58 | }; | |
59 | ||
60 | /** | |
61 | * A path matcher where a domain contains a resource if both the domain and the resource | |
62 | * can be interpreted as LDAP distinguished names and the resource DN starts with the | |
63 | * domain DN. | |
64 | * @since 0.3.0 | |
65 | */ | |
66 | 1 | protected static final PathMatcher LDAP_PATH_MATCHER = |
67 | new PathMatcher() { | |
68 | public String toDN (String path) { | |
69 | 166 | if (path.startsWith("/")) { |
70 | 15 | return path.substring(1); |
71 | } | |
72 | 151 | return path; |
73 | } | |
74 | ||
75 | 1 | public boolean contains (String domainPath, String resourcePath) { |
76 | try { | |
77 | 83 | final LdapName domainName = new LdapName(toDN(domainPath)); |
78 | 83 | final LdapName resourceName = new LdapName(toDN(resourcePath)); |
79 | 83 | return resourceName.startsWith(domainName); |
80 | 0 | } catch (NamingException e) { |
81 | 0 | return false; |
82 | } | |
83 | } | |
84 | }; | |
85 | ||
86 | /** | |
87 | * A path matcher where no resource is part of any domain. | |
88 | * @since 0.3.0 | |
89 | */ | |
90 | 1 | protected static final PathMatcher UNKNOWN_PATH_MATCHER = |
91 | new PathMatcher() { | |
92 | 1 | public boolean contains (String domainPath, String resourcePath) { |
93 | 0 | return false; |
94 | } | |
95 | }; | |
96 | ||
97 | /** | |
98 | * @since 0.3.0 | |
99 | */ | |
100 | protected static final int HTTP_DEFAULT_PORT = 80; | |
101 | ||
102 | /** | |
103 | * @since 0.3.0 | |
104 | */ | |
105 | protected static final int HTTPS_DEFAULT_PORT = 443; | |
106 | ||
107 | /** | |
108 | * @since 0.3.0 | |
109 | */ | |
110 | protected static final int LDAP_DEFAULT_PORT = 389; | |
111 | ||
112 | /** | |
113 | * @since 0.3.0 | |
114 | */ | |
115 | protected static final int LDAPS_DEFAULT_PORT = 636; | |
116 | ||
117 | /** | |
118 | * @since 0.1.0 | |
119 | */ | |
120 | private static final long serialVersionUID = -5330051822856507613L; | |
121 | ||
122 | //---- Constructors | |
123 | ||
124 | /** | |
125 | * Creates a domain that initially includes only the specified {@link URI}. | |
126 | * @param serialNumber the serial number of this part. | |
127 | * @param uri the URI of this domain. | |
128 | * @since 0.1.0 | |
129 | */ | |
130 | protected BasicDomain (SerialNumber serialNumber, URI uri) { | |
131 | 578 | super(DomainBean.class, serialNumber); |
132 | 578 | setIdentity(uri); |
133 | 578 | } |
134 | ||
135 | //---- Methods | |
136 | ||
137 | /** | |
138 | * Returns whether the specified domain contains the specified resource. | |
139 | * @param domain the {@link URI} of the domain. | |
140 | * @param resource the {@link URI} of the resource. | |
141 | * @return <code>true</code> if this domain considers the resource to be included in the domain. | |
142 | * @see #contains(URI) | |
143 | * @since 0.3.0 | |
144 | */ | |
145 | protected boolean contains (URI domain, URI resource) { | |
146 | 103 | if (!schemesMatch(domain.getScheme(), resource.getScheme())) { |
147 | 1 | return false; |
148 | } | |
149 | 102 | if (!hostsMatch(domain.getHost(), resource.getHost())) { |
150 | 2 | return false; |
151 | } | |
152 | 100 | if (!portsMatch(getPort(domain), getPort(resource))) { |
153 | 2 | return false; |
154 | } | |
155 | 98 | final PathMatcher pathMatcher = findPathMatcher(domain, resource); |
156 | 98 | return pathMatcher.contains(getPath(domain), getPath(resource)); |
157 | } | |
158 | ||
159 | /** | |
160 | * Returns whether the specified schemes are compatible. | |
161 | * @param domainScheme the scheme of the domain. | |
162 | * @param resourceScheme the scheme of the resource. | |
163 | * @return <code>true</code> if both schemes are <code>null</code>, if both schemes are equal, | |
164 | * or if only the domain scheme is specified. | |
165 | * @since 0.3.0 | |
166 | */ | |
167 | protected boolean schemesMatch (String domainScheme, String resourceScheme) { | |
168 | 103 | if (domainScheme == null) { |
169 | 78 | return resourceScheme == null; |
170 | } | |
171 | 25 | if (resourceScheme == null) { |
172 | 4 | return true; |
173 | } | |
174 | 21 | return domainScheme.equals(resourceScheme); |
175 | } | |
176 | ||
177 | /** | |
178 | * Returns whether the specified host names are compatible. | |
179 | * @param domainHost the host name of the domain. | |
180 | * @param resourceHost the host name of the resource. | |
181 | * @return <code>true</code> if both host names are <code>null</code>, if both host names | |
182 | * are equal, or if only the domain host is specified. | |
183 | * @since 0.3.0 | |
184 | */ | |
185 | protected boolean hostsMatch (String domainHost, String resourceHost) { | |
186 | 102 | if (domainHost == null) { |
187 | 85 | return resourceHost == null; |
188 | } | |
189 | 17 | if (resourceHost == null) { |
190 | 3 | return true; |
191 | } | |
192 | 14 | return domainHost.equals(resourceHost); |
193 | } | |
194 | ||
195 | /** | |
196 | * Returns the port number of the specified URI. | |
197 | * @param uri the {@link URI} whose (default) port number to return. | |
198 | * @return the port number specified in the URI or the default port number for the | |
199 | * URI scheme. If neither scheme nor port are specified or the scheme is unknown, | |
200 | * -1 is returned. | |
201 | * @since 0.3.0 | |
202 | */ | |
203 | protected int getPort (URI uri) { | |
204 | 200 | int port = uri.getPort(); |
205 | 200 | if (port < 0) { |
206 | 188 | port = getDefaultPort(uri.getScheme()); |
207 | } | |
208 | 200 | return port; |
209 | } | |
210 | ||
211 | /** | |
212 | * Returns the default port number for the specified URI scheme. | |
213 | * @param scheme a URI scheme. | |
214 | * @return the default port number for the scheme or -1 if the scheme is undefined or unknown. | |
215 | * @since 0.3.0 | |
216 | */ | |
217 | protected int getDefaultPort (String scheme) { | |
218 | 188 | if ("http".equalsIgnoreCase(scheme)) { |
219 | 12 | return HTTP_DEFAULT_PORT; |
220 | 176 | } else if ("https".equalsIgnoreCase(scheme)) { |
221 | 0 | return HTTPS_DEFAULT_PORT; |
222 | 176 | } else if ("ldap".equalsIgnoreCase(scheme)) { |
223 | 16 | return LDAP_DEFAULT_PORT; |
224 | 160 | } else if ("ldaps".equalsIgnoreCase(scheme)) { |
225 | 0 | return LDAPS_DEFAULT_PORT; |
226 | } | |
227 | 160 | return -1; |
228 | } | |
229 | ||
230 | /** | |
231 | * Returns whether port numbers of the specified domain and resource are compatible. | |
232 | * @param domainPort the port number of the domain. | |
233 | * @param resourcePort the port number of the resource. | |
234 | * @return <code>true</code> if both port numbers are unspecified, both port numbers | |
235 | * are equal, or the resource port is unspecified. | |
236 | * @since 0.3.0 | |
237 | */ | |
238 | protected boolean portsMatch (int domainPort, int resourcePort) { | |
239 | 100 | if (domainPort < 0) { |
240 | 78 | return resourcePort < 0; |
241 | } | |
242 | 22 | if (resourcePort < 0) { |
243 | 4 | return true; |
244 | } | |
245 | 18 | return domainPort == resourcePort; |
246 | } | |
247 | ||
248 | /** | |
249 | * Returns a path matcher for the specified domain and resource URI. | |
250 | * @param domain the {@link URI} of the domain. | |
251 | * @param resource the {@link URI} of the resource. | |
252 | * @return a suitable {@link PathMatcher}. The returned matcher is never <code>null</code>, | |
253 | * but may be {@link #UNKNOWN_PATH_MATCHER}. | |
254 | * @since 0.3.0 | |
255 | */ | |
256 | protected PathMatcher findPathMatcher (URI domain, URI resource) { | |
257 | 98 | PathMatcher pathMatcher = findPathMatcherForScheme(domain.getScheme()); |
258 | 98 | if (pathMatcher == UNKNOWN_PATH_MATCHER) { |
259 | 78 | pathMatcher = guessPathMatcherForPath(getPath(domain)); |
260 | } | |
261 | 98 | if (pathMatcher == UNKNOWN_PATH_MATCHER) { |
262 | 6 | pathMatcher = guessPathMatcherForPath(getPath(resource)); |
263 | } | |
264 | 98 | return pathMatcher; |
265 | } | |
266 | ||
267 | /** | |
268 | * Returns the path part of the specified URI. | |
269 | * @param uri a {@link URI}. | |
270 | * @return the path part of the URI or the scheme-specific part if the proper path is | |
271 | * <code>null</code>. | |
272 | * @since 0.3.0 | |
273 | */ | |
274 | protected String getPath (URI uri) { | |
275 | 280 | final String path = uri.getPath(); |
276 | 280 | if (path != null) { |
277 | 279 | return path; |
278 | } | |
279 | 1 | return uri.getSchemeSpecificPart(); |
280 | } | |
281 | ||
282 | /** | |
283 | * Derives a path matcher given a URI scheme. | |
284 | * @param scheme a scheme for which to return a suitable {@link PathMatcher}. | |
285 | * @return a {@link PathMatcher}, equal to {@link #UNKNOWN_PATH_MATCHER} if the scheme | |
286 | * is undefined or unknown. | |
287 | * @since 0.3.0 | |
288 | */ | |
289 | protected PathMatcher findPathMatcherForScheme (String scheme) { | |
290 | 98 | if ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)) { |
291 | 9 | return DIRECTORY_PATH_MATCHER; |
292 | } | |
293 | 89 | if ("ldap".equalsIgnoreCase(scheme) || "ldaps".equalsIgnoreCase(scheme)) { |
294 | 11 | return LDAP_PATH_MATCHER; |
295 | } | |
296 | 78 | return UNKNOWN_PATH_MATCHER; |
297 | } | |
298 | ||
299 | /** | |
300 | * Derives a path matcher from special characters in a path. | |
301 | * @param path the path part of a URI. | |
302 | * @return a {@link PathMatcher}, equal to {@link #UNKNOWN_PATH_MATCHER} if the scheme | |
303 | * cannot be derived from the contents of the path. | |
304 | * @since 0.3.0 | |
305 | */ | |
306 | protected PathMatcher guessPathMatcherForPath (String path) { | |
307 | 84 | if (path.indexOf('/') > 0) { |
308 | 6 | return DIRECTORY_PATH_MATCHER; |
309 | } | |
310 | 78 | if (path.indexOf(',') > 0) { |
311 | 72 | return LDAP_PATH_MATCHER; |
312 | } | |
313 | 6 | return UNKNOWN_PATH_MATCHER; |
314 | } | |
315 | ||
316 | //---- Domain | |
317 | ||
318 | /** | |
319 | * @since 0.1.0 | |
320 | */ | |
321 | public boolean contains (URI entity) { | |
322 | 103 | if (entity == null) { |
323 | 0 | return false; |
324 | } | |
325 | 103 | return contains(getIdentity().normalize(), entity.normalize()); |
326 | } | |
327 | ||
328 | //---- BasicPart | |
329 | ||
330 | /** | |
331 | * Checks that the part supplied is an domain. | |
332 | * @since 0.1.0 | |
333 | */ | |
334 | @Override | |
335 | protected final boolean comparablePart (BasicPart part) { | |
336 | 240 | return part instanceof Domain; |
337 | } | |
338 | ||
339 | /** | |
340 | * @since 0.1.0 | |
341 | */ | |
342 | @Override | |
343 | protected String getSimpleClassName () { | |
344 | 0 | return BasicDomain.class.getSimpleName(); |
345 | } | |
346 | ||
347 | } |