/*
*
* Copyright 2016 Netflix, Inc.
*
* Licensed 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.netflix.genie.web.security.oauth2.pingfederate;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Class to convert a map received from Ping Federate to a Spring Authentication object.
*
* @author tgianos
* @since 3.0.0
*/
public class PingFederateUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
protected static final String CLIENT_ID_KEY = "client_id";
protected static final String SCOPE_KEY = "scope";
protected static final String GENIE_PREFIX = "genie_";
protected static final String ROLE_PREFIX = "ROLE_";
private static final GrantedAuthority USER_AUTHORITY = new SimpleGrantedAuthority("ROLE_USER");
/**
* {@inheritDoc}
*/
//TODO: might be too much unnecessary validation in here
@Override
public Authentication extractAuthentication(final Map<String, ?> map) {
// Make sure we have a client id to use as the Principle
if (!map.containsKey(CLIENT_ID_KEY)) {
throw new InvalidTokenException("No client id key found in map");
}
final Object clientIdObject = map.get(CLIENT_ID_KEY);
if (!(clientIdObject instanceof String)) {
throw new InvalidTokenException("Client id wasn't string");
}
final String userName = (String) clientIdObject;
if (StringUtils.isBlank(userName)) {
throw new InvalidTokenException("Client id was blank. Unable to use as user name");
}
// Scopes were already validated in PingFederateRemoteTokenServices
final Object scopeObject = map.get(SCOPE_KEY);
if (!(scopeObject instanceof Collection)) {
throw new InvalidTokenException("Scopes were not a collection");
}
@SuppressWarnings("unchecked")
final Collection<String> scopes = (Collection<String>) scopeObject;
if (scopes.isEmpty()) {
throw new InvalidTokenException("No scopes available. Unable to authenticate");
}
// Default to user role
final Set<GrantedAuthority> authorities = Sets.newHashSet(USER_AUTHORITY);
scopes
.stream()
.filter(scope -> scope.contains(GENIE_PREFIX))
.distinct()
.forEach(
scope -> authorities.add(
new SimpleGrantedAuthority(
ROLE_PREFIX + StringUtils.removeStartIgnoreCase(scope, GENIE_PREFIX).toUpperCase()
)
)
);
return new UsernamePasswordAuthenticationToken(userName, "N/A", authorities);
}
}