Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
HelloWorldService |
|
| 3.4444444444444446;3.444 |
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.examples.ejb.server; | |
11 | ||
12 | import java.io.IOException; | |
13 | import java.net.URI; | |
14 | import java.net.URISyntaxException; | |
15 | import java.net.URL; | |
16 | import java.security.cert.CertificateException; | |
17 | import java.security.cert.CertificateFactory; | |
18 | import java.security.cert.X509Certificate; | |
19 | import java.util.ArrayList; | |
20 | import java.util.List; | |
21 | ||
22 | import javax.ejb.Stateless; | |
23 | ||
24 | import org.openpermis.AuthorizationService; | |
25 | import org.openpermis.AuthorizationServiceException; | |
26 | import org.openpermis.PolicyDecisionPoint; | |
27 | import org.openpermis.Subject; | |
28 | import org.openpermis.builder.AuthorizationServiceBuilder; | |
29 | import org.openpermis.cert.AttributeCertificateExtractorUtility; | |
30 | import org.openpermis.cert.BasicCertificateVerifier; | |
31 | import org.openpermis.cert.CertificateVerifier; | |
32 | import org.openpermis.policy.AccessDecision; | |
33 | import org.openpermis.repository.SubjectRepository; | |
34 | import org.openpermis.repository.SubjectRepositoryException; | |
35 | ||
36 | ||
37 | /** | |
38 | * An EJB implementation of the HelloWorld service. | |
39 | * <p>Access to a basic HelloWorld service is controlled with help of a policy decision | |
40 | * point (PDP). It serves as a policy enforcement point for the HelloWorld application.</p> | |
41 | * @since 0.3.0 | |
42 | */ | |
43 | @Stateless | |
44 | public class HelloWorldService | |
45 | implements HelloWorldServiceRemote | |
46 | { | |
47 | ||
48 | //---- Static | |
49 | ||
50 | /** | |
51 | * @since 0.3.0 | |
52 | */ | |
53 | 1 | protected static final URI TARGET_RESOURCE_URI = URI.create("cn=letterbox,o=post,c=ch"); |
54 | ||
55 | /** | |
56 | * @since 0.3.0 | |
57 | */ | |
58 | protected static final String ACTION_NAME = "collectLetters"; | |
59 | ||
60 | /** | |
61 | * Reads the SoA certificate from the classpath. | |
62 | * <p>A policy decision point needs a trusted public key of the source of authority (SoA) | |
63 | * to validate the attribute certificates (AC), including policies and roles. Future | |
64 | * implementations will allow a advanced public key infrastructure (PKI).</p> | |
65 | * @return the SoA certificate or {@code null} if it could not be read. | |
66 | * @since 0.3.0 | |
67 | */ | |
68 | private static final X509Certificate readSoaCertificate () { | |
69 | try { | |
70 | 0 | final URL soaCertificateUrl = |
71 | HelloWorldService.class.getResource("soa.cer"); | |
72 | 0 | final CertificateFactory factory = CertificateFactory.getInstance("X.509"); |
73 | 0 | return (X509Certificate) factory.generateCertificate(soaCertificateUrl.openStream()); |
74 | 0 | } catch (CertificateException e) { |
75 | 0 | System.out.println(" Cannot load SOA certificate. (" + e.getMessage() + ")"); |
76 | 0 | } catch (IOException e) { |
77 | 0 | System.out.println(" Cannot load SOA certificate. (" + e.getMessage() + ")"); |
78 | 0 | } |
79 | 0 | return null; |
80 | } | |
81 | ||
82 | /** | |
83 | * Creates a {@link PolicyDecisionPoint} from an attribute certificate located on the classpath. | |
84 | * @param certificateVerifier the certificate verifier used to verify the attribute | |
85 | * certificate containing the policy. | |
86 | * @return the {@link PolicyDecisionPoint} requested or {@code null} if it could not be created. | |
87 | * @since 0.3.0 | |
88 | */ | |
89 | private static final PolicyDecisionPoint createPolicyDecisionPoint ( | |
90 | CertificateVerifier certificateVerifier | |
91 | ) { | |
92 | 0 | final URL policyCertificateURL = |
93 | HelloWorldService.class.getResource("policy.ace"); | |
94 | try { | |
95 | 0 | return AttributeCertificateExtractorUtility. |
96 | createPolicyDecisionPoint(policyCertificateURL, certificateVerifier); | |
97 | 0 | } catch (Exception e) { |
98 | 0 | System.out.println("Failed to load policy decision point. (" + e.getMessage() + ")"); |
99 | } | |
100 | 0 | return null; |
101 | } | |
102 | ||
103 | /** | |
104 | * Creates a subject repository with subjects read from the classpath. | |
105 | * @param certificateVerifier The certificate verifier used to verify attribute certificates. | |
106 | * Used in the subject repository. | |
107 | * @return the subject repository or {@code null} in case of an error. | |
108 | * @since 0.3.0 | |
109 | */ | |
110 | private static final SubjectRepository readSubjectRepository ( | |
111 | CertificateVerifier certificateVerifier | |
112 | ) { | |
113 | try { | |
114 | 0 | return new HelloWorldSubjectRepository( |
115 | certificateVerifier, | |
116 | "john.ace", | |
117 | "sara.ace" | |
118 | ); | |
119 | 0 | } catch (SubjectRepositoryException e) { |
120 | 0 | System.out.println("Failed to create subject repository. (" + e.getMessage() + ")"); |
121 | } | |
122 | 0 | return null; |
123 | } | |
124 | ||
125 | /** | |
126 | * Creates a authorization for the hello world EJB. | |
127 | * @return the authorization service to use. | |
128 | * @since 0.3.0 | |
129 | */ | |
130 | private static final AuthorizationService createPolicyDecisionPoint () { | |
131 | 0 | final CertificateVerifier certificateVerifier = |
132 | new BasicCertificateVerifier(readSoaCertificate()); | |
133 | 0 | return new AuthorizationServiceBuilder(). |
134 | withSubjectsFrom(readSubjectRepository(certificateVerifier)). | |
135 | forPolicyDecisionPoint(createPolicyDecisionPoint(certificateVerifier)).build(); | |
136 | } | |
137 | ||
138 | /** | |
139 | * Creates a basic hello world service for this EJB. | |
140 | * @return the actual hello world service to delegate to. | |
141 | * @since 0.3.0 | |
142 | */ | |
143 | private static final HelloWorldServiceRemote createHelloWorldService () { | |
144 | 0 | return new BasicHelloWorldService(); |
145 | } | |
146 | ||
147 | //---- State | |
148 | ||
149 | /** | |
150 | * The injected authorization service. | |
151 | * @since 0.3.0 | |
152 | */ | |
153 | private final AuthorizationService authorizationService; | |
154 | ||
155 | /** | |
156 | * The actual service implementation to which we forward authorized requests. | |
157 | * @since 0.3.0 | |
158 | */ | |
159 | private final HelloWorldServiceRemote delegate; | |
160 | ||
161 | //---- Constructors | |
162 | ||
163 | /** | |
164 | * Creates a hello world EJB which uses a default PDP and HelloWorld service. | |
165 | * @see #createPolicyDecisionPoint() | |
166 | * @see #createHelloWorldService() | |
167 | * @since 0.3.0 | |
168 | */ | |
169 | public HelloWorldService () { | |
170 | 0 | this( |
171 | createPolicyDecisionPoint(), | |
172 | createHelloWorldService() | |
173 | ); | |
174 | 0 | } |
175 | ||
176 | /** | |
177 | * Creates an authorized HelloWorld service that uses the specified authorization service | |
178 | * context for retrieving roles and making access decisions. | |
179 | * @param authorizationService a {@link AuthorizationService}. | |
180 | * @param delegate the real service implementation to which authorized requests are forwarded. | |
181 | * @since 0.3.0 | |
182 | */ | |
183 | public HelloWorldService ( | |
184 | AuthorizationService authorizationService, | |
185 | HelloWorldServiceRemote delegate | |
186 | 2 | ) { |
187 | 2 | this.authorizationService = authorizationService; |
188 | 2 | this.delegate = delegate; |
189 | 2 | } |
190 | ||
191 | //---- Methods | |
192 | ||
193 | /** | |
194 | * Asserts that the service has been correctly initialized. | |
195 | * @throws HelloWorldException if the service is not correctly initialized. | |
196 | * @since 0.3.0 | |
197 | */ | |
198 | protected void assertInitialized () throws HelloWorldException { | |
199 | 2 | if (this.authorizationService == null) { |
200 | 0 | throw new HelloWorldException("PDP not initialized."); |
201 | 2 | } else if (this.delegate == null) { |
202 | 0 | throw new HelloWorldException("Delegate HelloWorldService not initialized."); |
203 | } | |
204 | 2 | } |
205 | ||
206 | //---- HelloWorldService | |
207 | ||
208 | /** | |
209 | * @since 0.1.0 | |
210 | */ | |
211 | public String getHelloMessage (String name) | |
212 | throws HelloWorldException | |
213 | { | |
214 | 2 | assertInitialized(); |
215 | // Find out who wants to access the service and which roles he has. | |
216 | // In an authenticated application you would get a java.net.Principal from an | |
217 | // authentication service and determine an identity from its name. | |
218 | // In a stateful application you would cache the retrieved subject in the current | |
219 | // session context to avoid repeated role lookups. | |
220 | final URI identity; | |
221 | try { | |
222 | 2 | identity = new URI(name); |
223 | 0 | } catch (URISyntaxException e) { |
224 | 0 | throw new HelloWorldException("Invalid name " + name, e); |
225 | 2 | } |
226 | final Subject subject; | |
227 | try { | |
228 | 2 | subject = this.authorizationService.retrieveSubject(identity); |
229 | 0 | } catch (AuthorizationServiceException e) { |
230 | 0 | throw new HelloWorldException("Cannot retrieve subject for " + name, e); |
231 | 2 | } |
232 | ||
233 | 2 | if (subject == null) { |
234 | 0 | throw new HelloWorldException("Unknown name " + name); |
235 | } | |
236 | ||
237 | // Identify the resource to protect. This could be a service URL. | |
238 | 2 | final URI resource = TARGET_RESOURCE_URI; |
239 | ||
240 | // Identify the action to perform on the protected resource. | |
241 | 2 | final String actionName = ACTION_NAME; |
242 | 2 | final List<Object> arguments = new ArrayList<Object>(); |
243 | ||
244 | try { | |
245 | // Ask the PDC for an access decision. | |
246 | 2 | final AccessDecision decision = this.authorizationService.getAccessDecision( |
247 | subject, resource, actionName, arguments | |
248 | ); | |
249 | ||
250 | 2 | if (decision.isAccessGranted()) { |
251 | // We are authorized to proceed, but still have to check obligations in the future. | |
252 | 1 | return this.delegate.getHelloMessage(name); |
253 | } | |
254 | ||
255 | // The decision is negative. We must inform the caller that he is not authorized. | |
256 | 1 | throw new HelloWorldException("Access denied for " + name); |
257 | ||
258 | 0 | } catch (AuthorizationServiceException e) { |
259 | 0 | throw new HelloWorldException("Cannot get access decision for " + name, e); |
260 | } | |
261 | } | |
262 | ||
263 | } |