/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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
*
* 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 org.apache.usergrid.security.providers;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.usergrid.management.ManagementService;
import org.apache.usergrid.persistence.EntityManager;
import org.apache.usergrid.persistence.entities.User;
import org.apache.usergrid.persistence.index.query.Identifier;
import org.apache.usergrid.security.tokens.exceptions.BadTokenException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Provider implementation for accessing Ping Identity
*
* @author zznate
*/
public class PingIdentityProvider extends AbstractProvider {
private static final Logger logger = LoggerFactory.getLogger(PingIdentityProvider.class);
private String apiUrl;
private String clientId;
private String clientSecret;
PingIdentityProvider(EntityManager entityManager, ManagementService managementService) {
super(entityManager, managementService);
}
@Override
public User createOrAuthenticate(String externalToken) throws BadTokenException {
Map<String, Object> pingUser = userFromResource(externalToken);
User user = null;
try {
user = managementService.getAppUserByIdentifier(entityManager.getApplication().getUuid(),
Identifier.fromEmail(pingUser.get("username").toString()));
} catch (Exception ex) {
logger.error("Unable to create/authenticate", ex);
// TODO what to do here?
}
if (user == null) {
Map<String, Object> properties = new LinkedHashMap<String, Object>();
properties.putAll(pingUser);
properties.put("activated", true);
properties.put("confirmed", true);
try {
user = entityManager.create("user", User.class, properties);
} catch (Exception ex) {
throw new BadTokenException("Could not create user for that token", ex);
}
} else {
user.setProperty("expiration", pingUser.get("expiration"));
try {
entityManager.update(user);
} catch (Exception ex) {
logger.error("Error in createOrAuthenticate()", ex);
}
}
return user;
}
@Override
void configure() {
try {
Map config = loadConfigurationFor();
if (config != null) {
apiUrl = (String) config.get("api_url");
clientId = (String) config.get("client_id");
clientSecret = (String) config.get("client_secret");
}
} catch (Exception ex) {
logger.error("Error in configure()", ex);
}
}
@Override
public Map<Object, Object> loadConfigurationFor() {
return loadConfigurationFor("pingIdentProvider");
}
@Override
public void saveToConfiguration(Map<String, Object> config) {
saveToConfiguration("pingIdentProvider", config);
}
@Override
Map<String, Object> userFromResource(String externalToken) {
MultivaluedMap<String, String> formData = getMultivaluedMapImpl();
formData.add("grant_type", "urn:pingidentity.com:oauth2:grant_type:validate_bearer");
formData.add("client_id", clientId);
formData.add("client_secret", clientSecret);
formData.add("token", externalToken);
JsonNode node = client.target(apiUrl).request()
.post(Entity.entity(formData, MediaType.APPLICATION_FORM_URLENCODED_TYPE), JsonNode.class);
String rawEmail = node.get("access_token").get("subject").asText();
Map<String, Object> userMap = new HashMap<String, Object>();
userMap.put("expiration", node.get("expires_in").asLong());
userMap.put("username", pingUsernameFrom(rawEmail));
userMap.put("name", "pinguser");
userMap.put("email", rawEmail);
return userMap;
}
public static String pingUsernameFrom(String rawEmail) {
return String.format("pinguser_%s", rawEmail);
}
public static long extractExpiration(User user) {
Long expiration = (Long) user.getProperty("expiration");
if (expiration == null) {
expiration = (long) 7200;
}
return expiration * 1000;
}
}