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.fit.core.reference;
20  
21  import com.nimbusds.jose.JOSEException;
22  import com.nimbusds.jose.JWSAlgorithm;
23  import com.nimbusds.jose.JWSHeader;
24  import com.nimbusds.jose.JWSVerifier;
25  import com.nimbusds.jose.crypto.MACVerifier;
26  import com.nimbusds.jose.jca.JCAContext;
27  import com.nimbusds.jose.util.Base64URL;
28  import com.nimbusds.jwt.JWTClaimsSet;
29  import java.util.List;
30  import java.util.Set;
31  import org.apache.commons.lang3.tuple.Pair;
32  import org.apache.syncope.common.lib.types.AnyTypeKind;
33  import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
34  import org.apache.syncope.core.persistence.api.dao.search.AttrCond;
35  import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
36  import org.apache.syncope.core.persistence.api.entity.user.User;
37  import org.apache.syncope.core.spring.security.AuthDataAccessor;
38  import org.apache.syncope.core.spring.security.JWTSSOProvider;
39  import org.apache.syncope.core.spring.security.SyncopeGrantedAuthority;
40  import org.springframework.transaction.annotation.Transactional;
41  
42  /**
43   * Custom implementation for internal JWT validation.
44   */
45  public class CustomJWTSSOProvider implements JWTSSOProvider {
46  
47      public static final String ISSUER = "custom-issuer";
48  
49      public static final String CUSTOM_KEY =
50              "XW3eTdntLa9Zsz2t4Vm6TNUya8xJEezFS7NVD3ZIZKOMdmSPMfi40rIvyBzXdbqD7TTsp6grcVW3AvRhZnFzZNaLdp6kJ2HXU9X9t2arVK"
51              + "42bIAp7XOw6aZg8v4OOXReZ9YkuAKtGwKC1JvPMKCz0c28AhJWd3YX5MpG6prXExQpFFVuweA6xTPxf06nYEFSOmKJ9ddJAcIx4Z8qyY"
52              + "mDJyNscMU8eVVM7aCR9zrCAHnjRZI2i6OnStAEVuqfGL25tK9AUKPVvyWljHNZ6ugXkstF873QaYJTBst1U2Zl9XsZnyeKrFEwwVHipp"
53              + "vfHwo2xu6VKySyJpZtaqVrjXFqpgFGRwEm890tCm8JhEG6GgJPqcnFHrYC180LqBZSjnNQGvA7eCSFVrABWcWnXDJCIHWbn0Wv153Vf4"
54              + "ZH75XEEYY53KsOS2T2GAmoqV3Izz7RL8O5dntgNLevl5gZb6MbYFURnQt0vALeObxMmv459FsXinzpAVihriOZWAudpN6Q";
55  
56      private final JWSVerifier delegate;
57  
58      private final AnySearchDAO anySearchDAO;
59  
60      private final AuthDataAccessor authDataAccessor;
61  
62      public CustomJWTSSOProvider(
63              final AnySearchDAO anySearchDAO,
64              final AuthDataAccessor authDataAccessor)
65              throws JOSEException {
66  
67          this.delegate = new MACVerifier(CUSTOM_KEY);
68          this.anySearchDAO = anySearchDAO;
69          this.authDataAccessor = authDataAccessor;
70      }
71  
72      @Override
73      public String getIssuer() {
74          return ISSUER;
75      }
76  
77      @Override
78      public Set<JWSAlgorithm> supportedJWSAlgorithms() {
79          return delegate.supportedJWSAlgorithms();
80      }
81  
82      @Override
83      public JCAContext getJCAContext() {
84          return delegate.getJCAContext();
85      }
86  
87      @Override
88      public boolean verify(
89              final JWSHeader header,
90              final byte[] signingInput,
91              final Base64URL signature) throws JOSEException {
92  
93          return delegate.verify(header, signingInput, signature);
94      }
95  
96      @Transactional(readOnly = true)
97      @Override
98      public Pair<User, Set<SyncopeGrantedAuthority>> resolve(final JWTClaimsSet jwtClaims) {
99          AttrCond userIdCond = new AttrCond();
100         userIdCond.setSchema("userId");
101         userIdCond.setType(AttrCond.Type.EQ);
102         userIdCond.setExpression(jwtClaims.getSubject());
103 
104         List<User> matching = anySearchDAO.search(SearchCond.getLeaf(userIdCond), AnyTypeKind.USER);
105         if (matching.size() == 1) {
106             User user = matching.get(0);
107             Set<SyncopeGrantedAuthority> authorities = authDataAccessor.getAuthorities(user.getUsername(), null);
108 
109             return Pair.of(user, authorities);
110         }
111 
112         return null;
113     }
114 }