blob: f8430aa716279d18cb36b63839655ccad8a3abe5 [file] [log] [blame]
margaretha34954472018-10-24 20:05:17 +02001package de.ids_mannheim.korap.oauth2.service;
2
3import java.util.Collection;
4import java.util.HashSet;
5import java.util.List;
6import java.util.Map;
7import java.util.Set;
8import java.util.stream.Collectors;
9import java.util.stream.Stream;
10
11import org.springframework.beans.factory.annotation.Autowired;
12
margaretha5f5d3ed2023-08-30 23:48:52 +020013import com.nimbusds.oauth2.sdk.OAuth2Error;
14
margaretha34954472018-10-24 20:05:17 +020015import de.ids_mannheim.korap.config.Attributes;
margaretha2df06602018-11-14 19:10:30 +010016import de.ids_mannheim.korap.constant.OAuth2Scope;
margaretha34954472018-10-24 20:05:17 +020017import de.ids_mannheim.korap.constant.TokenType;
18import de.ids_mannheim.korap.dao.AdminDao;
19import de.ids_mannheim.korap.exceptions.KustvaktException;
20import de.ids_mannheim.korap.exceptions.StatusCodes;
margaretha34954472018-10-24 20:05:17 +020021import de.ids_mannheim.korap.oauth2.dao.AccessScopeDao;
22import de.ids_mannheim.korap.oauth2.entity.AccessScope;
23import de.ids_mannheim.korap.security.context.TokenContext;
24
margaretha398f4722019-01-09 19:07:20 +010025/** Defines business logic related to OAuth2 scopes.
26 *
27 * @author margaretha
28 *
29 */
margaretha34954472018-10-24 20:05:17 +020030public class OAuth2ScopeServiceImpl implements OAuth2ScopeService {
31
32 @Autowired
33 private AccessScopeDao accessScopeDao;
34
35 @Autowired
36 private AdminDao adminDao;
37
margaretha2df06602018-11-14 19:10:30 +010038 /**
39 * Converts a set of scope strings to a set of {@link AccessScope}
40 *
41 * @param scopes
42 * @return
43 * @throws KustvaktException
margaretha34954472018-10-24 20:05:17 +020044 */
margaretha5f5d3ed2023-08-30 23:48:52 +020045 @Deprecated
margaretha34954472018-10-24 20:05:17 +020046 public Set<AccessScope> convertToAccessScope (Collection<String> scopes)
47 throws KustvaktException {
48
49 List<AccessScope> definedScopes = accessScopeDao.retrieveAccessScopes();
50 Set<AccessScope> requestedScopes =
51 new HashSet<AccessScope>(scopes.size());
52 int index;
53 OAuth2Scope oauth2Scope = null;
54 for (String scope : scopes) {
margaretha398f4722019-01-09 19:07:20 +010055 try {
56 oauth2Scope =
57 Enum.valueOf(OAuth2Scope.class, scope.toUpperCase());
margaretha34954472018-10-24 20:05:17 +020058 }
59 catch (IllegalArgumentException e) {
60 throw new KustvaktException(StatusCodes.INVALID_SCOPE,
margaretha5f5d3ed2023-08-30 23:48:52 +020061 "Invalid scope",
margaretha34954472018-10-24 20:05:17 +020062 OAuth2Error.INVALID_SCOPE);
63 }
margaretha398f4722019-01-09 19:07:20 +010064
margaretha34954472018-10-24 20:05:17 +020065 index = definedScopes.indexOf(new AccessScope(oauth2Scope));
66 if (index == -1) {
67 throw new KustvaktException(StatusCodes.INVALID_SCOPE,
margaretha5f5d3ed2023-08-30 23:48:52 +020068 "Invalid scope",
69 OAuth2Error.INVALID_SCOPE);
70 }
71 else {
72 requestedScopes.add(definedScopes.get(index));
73 }
74 }
75 return requestedScopes;
76 }
77
78 public Set<AccessScope> convertToAccessScope (String scopes)
79 throws KustvaktException {
80
margaretha93bfbea2023-11-06 21:09:21 +010081 String[] scopeArray = scopes.split("\\s+");
margaretha5f5d3ed2023-08-30 23:48:52 +020082 List<AccessScope> definedScopes = accessScopeDao.retrieveAccessScopes();
83 Set<AccessScope> requestedScopes =
84 new HashSet<AccessScope>(scopeArray.length);
85 int index;
86 OAuth2Scope oauth2Scope = null;
87 for (String scope : scopeArray) {
88 try {
89 oauth2Scope =
90 Enum.valueOf(OAuth2Scope.class, scope.toUpperCase());
91 }
92 catch (IllegalArgumentException e) {
93 throw new KustvaktException(StatusCodes.INVALID_SCOPE,
94 "Invalid scope",
95 OAuth2Error.INVALID_SCOPE);
96 }
97
98 index = definedScopes.indexOf(new AccessScope(oauth2Scope));
99 if (index == -1) {
100 throw new KustvaktException(StatusCodes.INVALID_SCOPE,
101 "Invalid scope",
margaretha34954472018-10-24 20:05:17 +0200102 OAuth2Error.INVALID_SCOPE);
103 }
104 else {
105 requestedScopes.add(definedScopes.get(index));
106 }
107 }
108 return requestedScopes;
109 }
110
margaretha34954472018-10-24 20:05:17 +0200111 public String convertAccessScopesToString (Set<AccessScope> scopes) {
112 Set<String> set = convertAccessScopesToStringSet(scopes);
113 return String.join(" ", set);
114 }
115
margaretha34954472018-10-24 20:05:17 +0200116 public Set<String> convertAccessScopesToStringSet (
117 Set<AccessScope> scopes) {
118 Set<String> set = scopes.stream().map(scope -> scope.toString())
119 .collect(Collectors.toSet());
120 return set;
121 }
122
margaretha2df06602018-11-14 19:10:30 +0100123 /**
124 * Simple reduction of requested scopes, i.e. excluding any scopes
125 * that are not default scopes for a specific authorization grant.
126 *
127 * @param scopes
128 * @param defaultScopes
129 * @return accepted scopes
margaretha34954472018-10-24 20:05:17 +0200130 */
margaretha34954472018-10-24 20:05:17 +0200131 public Set<String> filterScopes (Set<String> scopes,
132 Set<String> defaultScopes) {
133 Stream<String> stream = scopes.stream();
134 Set<String> filteredScopes =
135 stream.filter(scope -> defaultScopes.contains(scope))
136 .collect(Collectors.toSet());
137 return filteredScopes;
138 }
139
140 /* (non-Javadoc)
141 * @see de.ids_mannheim.korap.oauth2.service.OAuth2ScopeService#verifyScope(de.ids_mannheim.korap.security.context.TokenContext, de.ids_mannheim.korap.oauth2.constant.OAuth2Scope)
142 */
143 @Override
144 public void verifyScope (TokenContext context, OAuth2Scope requiredScope)
145 throws KustvaktException {
margaretha1960ea52023-02-28 11:20:15 +0100146 if (context == null) {
147 throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
148 "Authentication required. Please log in!");
149 }
150
margaretha34954472018-10-24 20:05:17 +0200151 if (!adminDao.isAdmin(context.getUsername())
152 && context.getTokenType().equals(TokenType.BEARER)) {
153 Map<String, Object> parameters = context.getParameters();
154 String authorizedScope = (String) parameters.get(Attributes.SCOPE);
155 if (!authorizedScope.contains(OAuth2Scope.ALL.toString())
156 && !authorizedScope.contains(requiredScope.toString())) {
157 throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
158 "Scope " + requiredScope + " is not authorized");
159 }
160 }
161 }
162
margaretha2df06602018-11-14 19:10:30 +0100163 /**
164 * Verify scopes given in a refresh request. The scopes must not
165 * include other scopes than those authorized in the original
166 * access token issued together with the refresh token.
167 *
168 * @param requestScopes
169 * requested scopes
170 * @param originalScopes
171 * authorized scopes
172 * @return a set of requested {@link AccessScope}
173 * @throws KustvaktException
margaretha34954472018-10-24 20:05:17 +0200174 */
margaretha34954472018-10-24 20:05:17 +0200175 public Set<AccessScope> verifyRefreshScope (Set<String> requestScopes,
176 Set<AccessScope> originalScopes) throws KustvaktException {
177 Set<AccessScope> requestedScopes = convertToAccessScope(requestScopes);
178 for (AccessScope scope : requestedScopes) {
179 if (!originalScopes.contains(scope)) {
180 throw new KustvaktException(StatusCodes.INVALID_SCOPE,
181 "Scope " + scope.getId() + " is not authorized.",
182 OAuth2Error.INVALID_SCOPE);
183 }
184 }
185 return requestedScopes;
186 }
187}