/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the License at the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apereo.portal.soffit.service;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import java.util.*;
import org.apereo.portal.soffit.model.v1_0.Bearer;
import org.springframework.stereotype.Service;
/**
* Responsible for issuing and parsing Bearer tokens.
*
* @since 5.0
*/
@Service
public class BearerService extends AbstractJwtService {
public Bearer createBearer(
String username,
Map<String, List<String>> attributes,
List<String> groups,
Date expires) {
final Claims claims = createClaims(Bearer.class, username, expires);
/*
* User attributes; attribute names that match registered attributes
* (https://www.iana.org/assignments/jwt/jwt.xhtml) will be
* automatically portable.
*/
for (Map.Entry<String, List<String>> y : attributes.entrySet()) {
final String name = y.getKey();
switch (y.getValue().size()) {
case 0:
// Do nothing...
break;
case 1:
// Model as a single value (in this a good idea?)
claims.put(name, y.getValue().get(0));
break;
default:
// Retain the collection
claims.put(name, y.getValue());
break;
}
}
// Groups
claims.put(JwtClaims.GROUPS.getName(), groups);
return new Bearer(generateEncryptedToken(claims), username, attributes, groups);
}
public Bearer parseBearerToken(String bearerToken) {
final Jws<Claims> claims = parseEncrypteToken(bearerToken, Bearer.class);
final String username = claims.getBody().getSubject();
final Map<String, List<String>> attributes = new HashMap<>();
for (Map.Entry<String, Object> y : claims.getBody().entrySet()) {
final String key = y.getKey();
if (JwtClaims.forName(key) != null) {
// Skip these; we handle these differently
continue;
}
if (y.getValue() instanceof List) {
@SuppressWarnings("unchecked")
final List<String> values = (List<String>) y.getValue();
attributes.put(key, values);
} else if (y.getValue() instanceof String) {
// Convert (back) to a single-item list
final String value = (String) y.getValue();
attributes.put(key, Collections.singletonList(value));
}
}
@SuppressWarnings("unchecked")
final List<String> groups = (List<String>) claims.getBody().get(JwtClaims.GROUPS.getName());
Bearer rslt = new Bearer(bearerToken, username, attributes, groups);
logger.debug("Produced the following Bearer for user '{}': {}", username, rslt);
return rslt;
}
}