View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.core.logic;
20  
21  import java.lang.reflect.Method;
22  import java.util.List;
23  import java.util.stream.Collectors;
24  import java.util.stream.Stream;
25  import org.apache.commons.lang3.ArrayUtils;
26  import org.apache.syncope.common.keymaster.client.api.ServiceOps;
27  import org.apache.syncope.common.lib.SyncopeClientException;
28  import org.apache.syncope.common.lib.to.ClientAppTO;
29  import org.apache.syncope.common.lib.types.AMEntitlement;
30  import org.apache.syncope.common.lib.types.ClientAppType;
31  import org.apache.syncope.common.lib.types.ClientExceptionType;
32  import org.apache.syncope.core.persistence.api.dao.CASSPClientAppDAO;
33  import org.apache.syncope.core.persistence.api.dao.NotFoundException;
34  import org.apache.syncope.core.persistence.api.dao.OIDCRPClientAppDAO;
35  import org.apache.syncope.core.persistence.api.dao.SAML2SPClientAppDAO;
36  import org.apache.syncope.core.persistence.api.entity.am.CASSPClientApp;
37  import org.apache.syncope.core.persistence.api.entity.am.ClientApp;
38  import org.apache.syncope.core.persistence.api.entity.am.ClientAppUtils;
39  import org.apache.syncope.core.persistence.api.entity.am.ClientAppUtilsFactory;
40  import org.apache.syncope.core.persistence.api.entity.am.OIDCRPClientApp;
41  import org.apache.syncope.core.persistence.api.entity.am.SAML2SPClientApp;
42  import org.apache.syncope.core.provisioning.api.data.ClientAppDataBinder;
43  import org.springframework.security.access.prepost.PreAuthorize;
44  import org.springframework.transaction.annotation.Transactional;
45  
46  public class ClientAppLogic extends AbstractTransactionalLogic<ClientAppTO> {
47  
48      protected final ServiceOps serviceOps;
49  
50      protected final ClientAppUtilsFactory clientAppUtilsFactory;
51  
52      protected final ClientAppDataBinder binder;
53  
54      protected final CASSPClientAppDAO casSPClientAppDAO;
55  
56      protected final OIDCRPClientAppDAO oidcRPClientAppDAO;
57  
58      protected final SAML2SPClientAppDAO saml2SPClientAppDAO;
59  
60      public ClientAppLogic(
61              final ServiceOps serviceOps,
62              final ClientAppUtilsFactory clientAppUtilsFactory,
63              final ClientAppDataBinder binder,
64              final CASSPClientAppDAO casSPClientAppDAO,
65              final OIDCRPClientAppDAO oidcRPClientAppDAO,
66              final SAML2SPClientAppDAO saml2SPClientAppDAO) {
67  
68          this.serviceOps = serviceOps;
69          this.clientAppUtilsFactory = clientAppUtilsFactory;
70          this.binder = binder;
71          this.casSPClientAppDAO = casSPClientAppDAO;
72          this.oidcRPClientAppDAO = oidcRPClientAppDAO;
73          this.saml2SPClientAppDAO = saml2SPClientAppDAO;
74      }
75  
76      @PreAuthorize("hasRole('" + AMEntitlement.CLIENTAPP_LIST + "')")
77      public <T extends ClientAppTO> List<T> list(final ClientAppType type) {
78          Stream<T> stream;
79  
80          switch (type) {
81              case OIDCRP:
82                  stream = oidcRPClientAppDAO.findAll().stream().map(binder::getClientAppTO);
83                  break;
84              case CASSP:
85                  stream = casSPClientAppDAO.findAll().stream().map(binder::getClientAppTO);
86                  break;
87              case SAML2SP:
88              default:
89                  stream = saml2SPClientAppDAO.findAll().stream().map(binder::getClientAppTO);
90          }
91  
92          return stream.collect(Collectors.toList());
93      }
94  
95      protected void checkType(final ClientAppType type, final ClientAppUtils clientAppUtils) {
96          if (clientAppUtils.getType() != type) {
97              SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRequest);
98              sce.getElements().add("Found " + type + ", expected " + clientAppUtils.getType());
99              throw sce;
100         }
101     }
102 
103     @PreAuthorize("hasRole('" + AMEntitlement.CLIENTAPP_READ + "')")
104     @Transactional(readOnly = true)
105     public <T extends ClientAppTO> T read(final ClientAppType type, final String key) {
106         switch (type) {
107             case OIDCRP:
108                 OIDCRPClientApp oidcrp = oidcRPClientAppDAO.find(key);
109                 if (oidcrp == null) {
110                     throw new NotFoundException("Client app " + key + " not found");
111                 }
112 
113                 checkType(type, clientAppUtilsFactory.getInstance(oidcrp));
114 
115                 return binder.getClientAppTO(oidcrp);
116             case CASSP:
117                 CASSPClientApp cassp = casSPClientAppDAO.find(key);
118                 if (cassp == null) {
119                     throw new NotFoundException("Client app " + key + " not found");
120                 }
121 
122                 checkType(type, clientAppUtilsFactory.getInstance(cassp));
123 
124                 return binder.getClientAppTO(cassp);
125             case SAML2SP:
126             default:
127                 SAML2SPClientApp saml2sp = saml2SPClientAppDAO.find(key);
128                 if (saml2sp == null) {
129                     throw new NotFoundException("Client app " + key + " not found");
130                 }
131 
132                 checkType(type, clientAppUtilsFactory.getInstance(saml2sp));
133 
134                 return binder.getClientAppTO(saml2sp);
135         }
136     }
137 
138     @PreAuthorize("hasRole('" + AMEntitlement.CLIENTAPP_CREATE + "')")
139     public <T extends ClientAppTO> T create(final ClientAppType type, final ClientAppTO clientAppTO) {
140         checkType(type, clientAppUtilsFactory.getInstance(clientAppTO));
141 
142         switch (type) {
143             case OIDCRP:
144                 return binder.getClientAppTO(oidcRPClientAppDAO.save(binder.create(clientAppTO)));
145             case CASSP:
146                 return binder.getClientAppTO(casSPClientAppDAO.save(binder.create(clientAppTO)));
147             case SAML2SP:
148             default:
149                 return binder.getClientAppTO(saml2SPClientAppDAO.save(binder.create(clientAppTO)));
150         }
151     }
152 
153     @PreAuthorize("hasRole('" + AMEntitlement.CLIENTAPP_UPDATE + "')")
154     public <T extends ClientAppTO> T update(final ClientAppType type, final ClientAppTO clientAppTO) {
155         checkType(type, clientAppUtilsFactory.getInstance(clientAppTO));
156 
157         switch (type) {
158             case OIDCRP:
159                 OIDCRPClientApp oidcrp = oidcRPClientAppDAO.find(clientAppTO.getKey());
160                 if (oidcrp == null) {
161                     throw new NotFoundException("Client app " + clientAppTO.getKey() + " not found");
162                 }
163                 binder.update(oidcrp, clientAppTO);
164                 return binder.getClientAppTO(oidcRPClientAppDAO.save(oidcrp));
165             case CASSP:
166                 CASSPClientApp cassp = casSPClientAppDAO.find(clientAppTO.getKey());
167                 if (cassp == null) {
168                     throw new NotFoundException("Client app " + clientAppTO.getKey() + " not found");
169                 }
170                 binder.update(cassp, clientAppTO);
171                 return binder.getClientAppTO(casSPClientAppDAO.save(cassp));
172             case SAML2SP:
173             default:
174                 SAML2SPClientApp saml2sp = saml2SPClientAppDAO.find(clientAppTO.getKey());
175                 if (saml2sp == null) {
176                     throw new NotFoundException("Client app " + clientAppTO.getKey() + " not found");
177                 }
178                 binder.update(saml2sp, clientAppTO);
179                 return binder.getClientAppTO(saml2SPClientAppDAO.save(saml2sp));
180         }
181     }
182 
183     @PreAuthorize("hasRole('" + AMEntitlement.CLIENTAPP_DELETE + "')")
184     public <T extends ClientAppTO> T delete(final ClientAppType type, final String key) {
185         final T deleted;
186         switch (type) {
187             case OIDCRP:
188                 OIDCRPClientApp oidcrp = oidcRPClientAppDAO.find(key);
189                 if (oidcrp == null) {
190                     throw new NotFoundException("Client app " + key + " not found");
191                 }
192                 oidcRPClientAppDAO.delete(oidcrp);
193                 deleted = binder.getClientAppTO(oidcrp);
194                 break;
195             case CASSP:
196                 CASSPClientApp cassp = casSPClientAppDAO.find(key);
197                 if (cassp == null) {
198                     throw new NotFoundException("Client app " + key + " not found");
199                 }
200                 casSPClientAppDAO.delete(cassp);
201                 deleted = binder.getClientAppTO(cassp);
202                 break;
203             case SAML2SP:
204             default:
205                 SAML2SPClientApp saml2sp = saml2SPClientAppDAO.find(key);
206                 if (saml2sp == null) {
207                     throw new NotFoundException("Client app " + key + " not found");
208                 }
209                 saml2SPClientAppDAO.delete(saml2sp);
210                 deleted = binder.getClientAppTO(saml2sp);
211         }
212 
213         return deleted;
214     }
215 
216     @Override
217     protected ClientAppTO resolveReference(final Method method, final Object... args)
218             throws UnresolvedReferenceException {
219 
220         if (ArrayUtils.isEmpty(args) || args.length != 2) {
221             throw new UnresolvedReferenceException();
222         }
223 
224         try {
225             final String key;
226             final ClientAppType type;
227 
228             if (args[0] instanceof ClientAppType) {
229                 type = (ClientAppType) args[0];
230             } else {
231                 throw new RuntimeException("Invalid ClientApp type");
232             }
233 
234             if (args[1] instanceof String) {
235                 key = (String) args[1];
236             } else if (args[1] instanceof ClientAppTO) {
237                 key = ((ClientAppTO) args[1]).getKey();
238             } else {
239                 throw new RuntimeException("Invalid ClientApp key");
240             }
241 
242             final ClientApp clientApp;
243             switch (type) {
244                 case CASSP:
245                     clientApp = casSPClientAppDAO.find(key);
246                     break;
247                 case SAML2SP:
248                     clientApp = saml2SPClientAppDAO.find(key);
249                     break;
250                 case OIDCRP:
251                     clientApp = oidcRPClientAppDAO.find(key);
252                     break;
253                 default:
254                     throw new RuntimeException("Unexpected ClientApp type");
255             }
256 
257             return binder.getClientAppTO(clientApp);
258         } catch (Throwable t) {
259             throw new UnresolvedReferenceException();
260         }
261     }
262 }