/* * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. * * Copyright (c) 2014, Gluu */ package org.xdi.oxauth.servlet; import org.apache.commons.lang.StringUtils; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; import org.slf4j.Logger; import org.xdi.ldap.model.GluuStatus; import org.xdi.model.GluuAttribute; import org.xdi.oxauth.model.common.Scope; import org.xdi.oxauth.model.common.ScopeType; import org.xdi.oxauth.model.configuration.AppConfiguration; import org.xdi.oxauth.model.uma.UmaScopeType; import org.xdi.oxauth.service.AttributeService; import org.xdi.oxauth.service.ScopeService; import org.xdi.oxauth.service.external.ExternalAuthenticationService; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.List; import java.util.Map; import java.util.Set; import static org.xdi.oxauth.model.configuration.ConfigurationResponseClaim.*; /** * @author Javier Rojas Blum * @author Yuriy Movchan Date: 2016/04/26 * @version April 26, 2017 */ @WebServlet(urlPatterns = "/.well-known/openid-configuration") public class OpenIdConfiguration extends HttpServlet { private static final long serialVersionUID = -8224898157373678903L; @Inject private Logger log; @Inject private AppConfiguration appConfiguration; @Inject private AttributeService attributeService; @Inject private ScopeService scopeService; @Inject private ExternalAuthenticationService externalAuthenticationService; /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> * methods. * * @param servletRequest servlet request * @param servletResponse servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException { final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; final HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; httpResponse.setContentType("application/json"); PrintWriter out = httpResponse.getWriter(); try { JSONObject jsonObj = new JSONObject(); jsonObj.put(ISSUER, appConfiguration.getIssuer()); jsonObj.put(AUTHORIZATION_ENDPOINT, appConfiguration.getAuthorizationEndpoint()); jsonObj.put(TOKEN_ENDPOINT, appConfiguration.getTokenEndpoint()); jsonObj.put(USER_INFO_ENDPOINT, appConfiguration.getUserInfoEndpoint()); jsonObj.put(CLIENT_INFO_ENDPOINT, appConfiguration.getClientInfoEndpoint()); jsonObj.put(CHECK_SESSION_IFRAME, appConfiguration.getCheckSessionIFrame()); jsonObj.put(END_SESSION_ENDPOINT, appConfiguration.getEndSessionEndpoint()); jsonObj.put(JWKS_URI, appConfiguration.getJwksUri()); jsonObj.put(REGISTRATION_ENDPOINT, appConfiguration.getRegistrationEndpoint()); jsonObj.put(ID_GENERATION_ENDPOINT, appConfiguration.getIdGenerationEndpoint()); jsonObj.put(INTROSPECTION_ENDPOINT, appConfiguration.getIntrospectionEndpoint()); JSONArray scopesSupported = new JSONArray(); for (Scope scope : scopeService.getAllScopesList()) { boolean isUmaAuthorization = UmaScopeType.AUTHORIZATION.getValue() .equals(scope.getDisplayName()); boolean isUmaProtection = UmaScopeType.PROTECTION.getValue().equals(scope.getDisplayName()); if (!isUmaAuthorization && !isUmaProtection) scopesSupported.put(scope.getDisplayName()); } if (scopesSupported.length() > 0) { jsonObj.put(SCOPES_SUPPORTED, scopesSupported); } JSONArray responseTypesSupported = new JSONArray(); for (String responseType : appConfiguration.getResponseTypesSupported()) { responseTypesSupported.put(responseType); } if (responseTypesSupported.length() > 0) { jsonObj.put(RESPONSE_TYPES_SUPPORTED, responseTypesSupported); } JSONArray grantTypesSupported = new JSONArray(); for (String grantType : appConfiguration.getGrantTypesSupported()) { grantTypesSupported.put(grantType); } if (grantTypesSupported.length() > 0) { jsonObj.put(GRANT_TYPES_SUPPORTED, grantTypesSupported); } JSONArray acrValuesSupported = new JSONArray(); for (String acr : externalAuthenticationService.getAcrValuesList()) { acrValuesSupported.put(acr); } jsonObj.put(ACR_VALUES_SUPPORTED, acrValuesSupported); jsonObj.put(AUTH_LEVEL_MAPPING, createAuthLevelMapping()); JSONArray subjectTypesSupported = new JSONArray(); for (String subjectType : appConfiguration.getSubjectTypesSupported()) { subjectTypesSupported.put(subjectType); } if (subjectTypesSupported.length() > 0) { jsonObj.put(SUBJECT_TYPES_SUPPORTED, subjectTypesSupported); } JSONArray userInfoSigningAlgValuesSupported = new JSONArray(); for (String userInfoSigningAlg : appConfiguration.getUserInfoSigningAlgValuesSupported()) { userInfoSigningAlgValuesSupported.put(userInfoSigningAlg); } if (userInfoSigningAlgValuesSupported.length() > 0) { jsonObj.put(USER_INFO_SIGNING_ALG_VALUES_SUPPORTED, userInfoSigningAlgValuesSupported); } JSONArray userInfoEncryptionAlgValuesSupported = new JSONArray(); for (String userInfoEncryptionAlg : appConfiguration.getUserInfoEncryptionAlgValuesSupported()) { userInfoEncryptionAlgValuesSupported.put(userInfoEncryptionAlg); } if (userInfoEncryptionAlgValuesSupported.length() > 0) { jsonObj.put(USER_INFO_ENCRYPTION_ALG_VALUES_SUPPORTED, userInfoEncryptionAlgValuesSupported); } JSONArray userInfoEncryptionEncValuesSupported = new JSONArray(); for (String userInfoEncryptionEnc : appConfiguration.getUserInfoEncryptionEncValuesSupported()) { userInfoEncryptionEncValuesSupported.put(userInfoEncryptionEnc); } if (userInfoEncryptionAlgValuesSupported.length() > 0) { jsonObj.put(USER_INFO_ENCRYPTION_ENC_VALUES_SUPPORTED, userInfoEncryptionAlgValuesSupported); } JSONArray idTokenSigningAlgValuesSupported = new JSONArray(); for (String idTokenSigningAlg : appConfiguration.getIdTokenSigningAlgValuesSupported()) { idTokenSigningAlgValuesSupported.put(idTokenSigningAlg); } if (idTokenSigningAlgValuesSupported.length() > 0) { jsonObj.put(ID_TOKEN_SIGNING_ALG_VALUES_SUPPORTED, idTokenSigningAlgValuesSupported); } JSONArray idTokenEncryptionAlgValuesSupported = new JSONArray(); for (String idTokenEncryptionAlg : appConfiguration.getIdTokenEncryptionAlgValuesSupported()) { idTokenEncryptionAlgValuesSupported.put(idTokenEncryptionAlg); } if (idTokenEncryptionAlgValuesSupported.length() > 0) { jsonObj.put(ID_TOKEN_ENCRYPTION_ALG_VALUES_SUPPORTED, idTokenEncryptionAlgValuesSupported); } JSONArray idTokenEncryptionEncValuesSupported = new JSONArray(); for (String idTokenEncryptionEnc : appConfiguration.getIdTokenEncryptionEncValuesSupported()) { idTokenEncryptionEncValuesSupported.put(idTokenEncryptionEnc); } if (idTokenEncryptionEncValuesSupported.length() > 0) { jsonObj.put(ID_TOKEN_ENCRYPTION_ENC_VALUES_SUPPORTED, idTokenEncryptionEncValuesSupported); } JSONArray requestObjectSigningAlgValuesSupported = new JSONArray(); for (String requestObjectSigningAlg : appConfiguration.getRequestObjectSigningAlgValuesSupported()) { requestObjectSigningAlgValuesSupported.put(requestObjectSigningAlg); } if (requestObjectSigningAlgValuesSupported.length() > 0) { jsonObj.put(REQUEST_OBJECT_SIGNING_ALG_VALUES_SUPPORTED, requestObjectSigningAlgValuesSupported); } JSONArray requestObjectEncryptionAlgValuesSupported = new JSONArray(); for (String requestObjectEncryptionAlg : appConfiguration .getRequestObjectEncryptionAlgValuesSupported()) { requestObjectEncryptionAlgValuesSupported.put(requestObjectEncryptionAlg); } if (requestObjectEncryptionAlgValuesSupported.length() > 0) { jsonObj.put(REQUEST_OBJECT_ENCRYPTION_ALG_VALUES_SUPPORTED, requestObjectEncryptionAlgValuesSupported); } JSONArray requestObjectEncryptionEncValuesSupported = new JSONArray(); for (String requestObjectEncryptionEnc : appConfiguration .getRequestObjectEncryptionEncValuesSupported()) { requestObjectEncryptionEncValuesSupported.put(requestObjectEncryptionEnc); } if (requestObjectEncryptionEncValuesSupported.length() > 0) { jsonObj.put(REQUEST_OBJECT_ENCRYPTION_ENC_VALUES_SUPPORTED, requestObjectEncryptionEncValuesSupported); } JSONArray tokenEndpointAuthMethodsSupported = new JSONArray(); for (String tokenEndpointAuthMethod : appConfiguration.getTokenEndpointAuthMethodsSupported()) { tokenEndpointAuthMethodsSupported.put(tokenEndpointAuthMethod); } if (tokenEndpointAuthMethodsSupported.length() > 0) { jsonObj.put(TOKEN_ENDPOINT_AUTH_METHODS_SUPPORTED, tokenEndpointAuthMethodsSupported); } JSONArray tokenEndpointAuthSigningAlgValuesSupported = new JSONArray(); for (String tokenEndpointAuthSigningAlg : appConfiguration .getTokenEndpointAuthSigningAlgValuesSupported()) { tokenEndpointAuthSigningAlgValuesSupported.put(tokenEndpointAuthSigningAlg); } if (tokenEndpointAuthSigningAlgValuesSupported.length() > 0) { jsonObj.put(TOKEN_ENDPOINT_AUTH_SIGNING_ALG_VALUES_SUPPORTED, tokenEndpointAuthSigningAlgValuesSupported); } JSONArray displayValuesSupported = new JSONArray(); for (String display : appConfiguration.getDisplayValuesSupported()) { displayValuesSupported.put(display); } if (displayValuesSupported.length() > 0) { jsonObj.put(DISPLAY_VALUES_SUPPORTED, displayValuesSupported); } JSONArray claimTypesSupported = new JSONArray(); for (String claimType : appConfiguration.getClaimTypesSupported()) { claimTypesSupported.put(claimType); } if (claimTypesSupported.length() > 0) { jsonObj.put(CLAIM_TYPES_SUPPORTED, claimTypesSupported); } JSONArray claimsSupported = new JSONArray(); List<GluuAttribute> gluuAttributes = attributeService.getAllAttributes(); // Preload all scopes to avoid sending request to LDAP per // claim List<org.xdi.oxauth.model.common.Scope> scopes = scopeService.getAllScopesList(); for (GluuAttribute gluuAttribute : gluuAttributes) { if (GluuStatus.ACTIVE.equals(gluuAttribute.getStatus())) { String claimName = gluuAttribute.getOxAuthClaimName(); if (StringUtils.isNotBlank(claimName)) { List<org.xdi.oxauth.model.common.Scope> scopesByClaim = scopeService .getScopesByClaim(scopes, gluuAttribute.getDn()); for (org.xdi.oxauth.model.common.Scope scope : scopesByClaim) { if (ScopeType.OPENID.equals(scope.getScopeType())) { claimsSupported.put(claimName); break; } } } } } if (claimsSupported.length() > 0) { jsonObj.put(CLAIMS_SUPPORTED, claimsSupported); } jsonObj.put(SERVICE_DOCUMENTATION, appConfiguration.getServiceDocumentation()); JSONArray claimsLocalesSupported = new JSONArray(); for (String claimLocale : appConfiguration.getClaimsLocalesSupported()) { claimsLocalesSupported.put(claimLocale); } if (claimsLocalesSupported.length() > 0) { jsonObj.put(CLAIMS_LOCALES_SUPPORTED, claimsLocalesSupported); } JSONArray uiLocalesSupported = new JSONArray(); for (String uiLocale : appConfiguration.getUiLocalesSupported()) { uiLocalesSupported.put(uiLocale); } if (uiLocalesSupported.length() > 0) { jsonObj.put(UI_LOCALES_SUPPORTED, uiLocalesSupported); } jsonObj.put(SCOPE_TO_CLAIMS_MAPPING, createScopeToClaimsMapping()); jsonObj.put(CLAIMS_PARAMETER_SUPPORTED, appConfiguration.getClaimsParameterSupported()); jsonObj.put(REQUEST_PARAMETER_SUPPORTED, appConfiguration.getRequestParameterSupported()); jsonObj.put(REQUEST_URI_PARAMETER_SUPPORTED, appConfiguration.getRequestUriParameterSupported()); jsonObj.put(REQUIRE_REQUEST_URI_REGISTRATION, appConfiguration.getRequireRequestUriRegistration()); jsonObj.put(OP_POLICY_URI, appConfiguration.getOpPolicyUri()); jsonObj.put(OP_TOS_URI, appConfiguration.getOpTosUri()); jsonObj.put(FRONTCHANNEL_LOGOUT_SUPPORTED, "true"); jsonObj.put(FRONTCHANNEL_LOGOUT_SESSION_SUPPORTED, "true"); jsonObj.put(FRONT_CHANNEL_LOGOUT_SESSION_SUPPORTED, appConfiguration.getFrontChannelLogoutSessionSupported()); out.println(jsonObj.toString(4).replace("\\/", "/")); } catch (JSONException e) { log.error(e.getMessage(), e); } catch (Exception e) { log.error(e.getMessage(), e); } finally { out.close(); } } /** * @deprecated theses params: * <ul> * <li>id_generation_endpoint</li> * <li>introspection_endpoint</li> * <li>auth_level_mapping</li> * <li>scope_to_claims_mapping</li> * </ul> * will be moved from /.well-known/openid-configuration * to /.well-known/gluu-configuration */ @Deprecated private JSONArray createScopeToClaimsMapping() { final JSONArray result = new JSONArray(); try { for (Scope scope : scopeService.getAllScopesList()) { final JSONArray claimsList = new JSONArray(); final JSONObject mapping = new JSONObject(); mapping.put(scope.getDisplayName(), claimsList); result.put(mapping); final List<String> claimIdList = scope.getOxAuthClaims(); if (claimIdList != null && !claimIdList.isEmpty()) { for (String claimDn : claimIdList) { final GluuAttribute attribute = attributeService.getAttributeByDn(claimDn); final String claimName = attribute.getOxAuthClaimName(); if (StringUtils.isNotBlank(claimName)) { claimsList.put(claimName); } } } } } catch (Exception e) { log.error(e.getMessage(), e); } return result; } /** * @deprecated theses params: * <ul> * <li>id_generation_endpoint</li> * <li>introspection_endpoint</li> * <li>auth_level_mapping</li> * <li>scope_to_claims_mapping</li> * </ul> * will be moved from /.well-known/openid-configuration to * /.well-known/gluu-configuration */ @Deprecated private JSONObject createAuthLevelMapping() { final JSONObject mappings = new JSONObject(); try { Map<Integer, Set<String>> map = externalAuthenticationService.levelToAcrMapping(); for (Integer level : map.keySet()) mappings.put(level.toString(), map.get(level)); } catch (Exception e) { log.error(e.getMessage(), e); } return mappings; } /** * Handles the HTTP <code>GET</code> method. * * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. * * @return a String containing servlet description */ @Override public String getServletInfo() { return "OpenID Provider Configuration Information"; } }