/** * Establish the SAML2IDP using the PROXY_URLPATH_CONTEXT from the session<br> * Also puts the SAML2IDP's EntityId in the Session as PROXY_SHADOWED_ENTITYID<br> * <br> * When no SAML2IDP match could be made, there will be no PROXY_SHADOWED_ENTITYID attribute * written in the session, and null is returned. * * @param oAttributes Session Attributes * @param oURLPathContext non-null initialized URLPathContext instance to process * @return SAML2IDP organization as established, or null when no match could be made */ protected SAML2IDP processURLPathContext( ISessionAttributes oAttributes, URLPathContext oURLPathContext) throws OAException { // Did we try to find a match before? if (oAttributes.contains( com.alfaariss.oa.util.session.ProxyAttributes.class, com.alfaariss.oa.util.session.ProxyAttributes.PROXY_SHADOWED_IDPID)) { String sShadowedEntityId = (String) oAttributes.get( com.alfaariss.oa.util.session.ProxyAttributes.class, com.alfaariss.oa.util.session.ProxyAttributes.PROXY_SHADOWED_IDPID); // Re-use this intelligence, and return the SAML2IDP instance IIDP oIDP = _organizationStorage.getIDP(sShadowedEntityId); if (oIDP instanceof SAML2IDP) { _logger.info("Found IDP '" + sShadowedEntityId + "' from previous URLPath Context match"); return (SAML2IDP) oIDP; } else { _logger.warn( "Non-SAML2IDP found in IDP Storage - inform developers of this condition! (1)"); return null; } } String sIValue = oURLPathContext.getParams().get("i"); if (sIValue == null) { _logger.info("No 'i' value found in URLPath Context path ('" + oURLPathContext + "')"); return null; } List<IIDP> lAllIDPs = _organizationStorage.getAll(); for (IIDP oIDP : lAllIDPs) { String sIDPEntityIdHash = DigestUtils.shaHex(oIDP.getID()); if (sIDPEntityIdHash.equalsIgnoreCase(sIValue)) { _logger.info("Found IDP '" + oIDP.getID() + "' in matching URLPath Context"); if (oIDP instanceof SAML2IDP) { // Store the IDP that was found on the map oAttributes.put( com.alfaariss.oa.util.session.ProxyAttributes.class, com.alfaariss.oa.util.session.ProxyAttributes.PROXY_SHADOWED_IDPID, oIDP.getID()); // Return result return (SAML2IDP) oIDP; } else { _logger.warn( "Non-SAML2IDP found in IDP Storage - inform developers of this condition! (2)"); return null; } } } _logger.info("No IDP found for provided i"); return null; }
/** * Extracts the forced IDP list from the session. * * @param session The authentication session. * @return The forced IDPs. * @throws OAException If organization storage exist check can't be performed. */ @SuppressWarnings("unchecked") private List<String> getForcedIDPs(ISession session) throws OAException { List<String> retval = new Vector<String>(); IUser oUser = session.getUser(); if (oUser instanceof SAMLRemoteUser) { SAMLRemoteUser remoteUser = (SAMLRemoteUser) oUser; String sRemoteIdP = remoteUser.getOrganization(); if (sRemoteIdP != null && _organizationStorage.exists(sRemoteIdP)) { StringBuffer sbDebug = new StringBuffer(); sbDebug.append("There is a Remote SAML User available in session with ID '"); sbDebug.append(session.getId()); sbDebug.append("' that is known at remote IdP '"); sbDebug.append(sRemoteIdP); sbDebug.append("' so this IdP will be forced"); _logger.debug(sbDebug.toString()); retval.add(sRemoteIdP); return retval; } } ISessionAttributes atts = session.getAttributes(); String sGetComplete = (String) atts.get(ProxyAttributes.class, ProxyAttributes.IDPLIST_GETCOMPLETE); if (sGetComplete != null) { _logger.debug( "Using proxy attribute: " + ProxyAttributes.IDPLIST_GETCOMPLETE + ": " + sGetComplete); // getcomplete IDPList idpList = null; try { if (_mRemoteIDPLists.containsKey(sGetComplete)) { idpList = _mRemoteIDPLists.get(sGetComplete).getList(); } else { RemoteIDPListEntry entry = new RemoteIDPListEntry(sGetComplete, 1000); idpList = entry.getList(); // DD Add the RemoteIDPListEntry to a map for caching purposes; The getEntry() retrieves // the list from the url. _mRemoteIDPLists.put(sGetComplete, entry); } if (idpList != null) { for (IDPEntry entry : idpList.getIDPEntrys()) { retval.add(entry.getProviderID()); } } } catch (ResourceException e) { _logger.warn("Failed retrieval of IDPList from GetComplete URL: " + sGetComplete, e); } } List<SAML2IDPEntry> idpList = (List<SAML2IDPEntry>) atts.get(ProxyAttributes.class, ProxyAttributes.IDPLIST); if (idpList != null) { if (_logger.isDebugEnabled()) { StringBuffer sbMessage = new StringBuffer("Using proxy attribute "); sbMessage.append(ProxyAttributes.IDPLIST); sbMessage.append(": ").append(idpList); _logger.debug(sbMessage); } for (SAML2IDPEntry entry : idpList) { // DD We currently ignore the proxied SAML2IDPEntry.getName() (friendlyname) and // SAML2IDPEntry.getLoc() String sID = entry.getProviderID(); if (sID != null) { if (!retval.contains(sID)) retval.add(sID); } } } Collection cForcedOrganizations = (Collection) atts.get( com.alfaariss.oa.util.session.ProxyAttributes.class, com.alfaariss.oa.util.session.ProxyAttributes.FORCED_ORGANIZATIONS); if (cForcedOrganizations != null) { if (_logger.isDebugEnabled()) { StringBuffer sbMessage = new StringBuffer("Using proxy attribute "); sbMessage.append(com.alfaariss.oa.util.session.ProxyAttributes.FORCED_ORGANIZATIONS); sbMessage.append(": ").append(cForcedOrganizations); _logger.debug(sbMessage); } for (Object oForceOrganization : cForcedOrganizations) { String sForceOrganization = (String) oForceOrganization; if (!retval.contains(sForceOrganization)) retval.add(sForceOrganization); } } return retval; }
/** * Requestor selection based on RemoteASelectMethod.authenticate. * * <p>When implementing Synchronous (querying) authentication, this method should be adapted. - * Warnings * * @see * com.alfaariss.oa.sso.authentication.web.IWebAuthenticationMethod#authenticate(javax.servlet.http.HttpServletRequest, * javax.servlet.http.HttpServletResponse, com.alfaariss.oa.api.session.ISession) */ @SuppressWarnings("unchecked") public UserEvent authenticate( HttpServletRequest request, HttpServletResponse response, ISession session) throws OAException { try { ISessionAttributes oAttributes = session.getAttributes(); // check proxy att: Integer intCnt = (Integer) oAttributes.get(ProxyAttributes.class, ProxyAttributes.PROXYCOUNT); if (intCnt != null && intCnt <= 0) { _logger.debug("No more authentication proxying allowed: " + intCnt); _eventLogger.info( new UserEventLogItem( session, request.getRemoteAddr(), UserEvent.AUTHN_METHOD_FAILED, this, "ProxyCount <= 0")); return UserEvent.AUTHN_METHOD_FAILED; } SAML2IDP organization = null; List<Warnings> warnings = null; // Figure out whether there exists a pre-selected organization in the URLPath context URLPathContext oURLPathContext = (URLPathContext) oAttributes.get( com.alfaariss.oa.util.session.ProxyAttributes.class, com.alfaariss.oa.util.session.ProxyAttributes.PROXY_URLPATH_CONTEXT); if (oURLPathContext != null) { organization = processURLPathContext(oAttributes, oURLPathContext); } if (organization != null) { _logger.info("Established organization from URLPathContext: " + organization.getID()); // Add to Session context if it is not there yet if (!oAttributes.contains( SAML2AuthenticationMethod.class, _sMethodId + "." + SELECTED_ORGANIZATION)) { oAttributes.put( SAML2AuthenticationMethod.class, _sMethodId, SELECTED_ORGANIZATION, organization); } } else { if (oAttributes.contains( SAML2AuthenticationMethod.class, _sMethodId + "." + SELECTED_ORGANIZATION)) { organization = (SAML2IDP) oAttributes.get( SAML2AuthenticationMethod.class, _sMethodId + "." + SELECTED_ORGANIZATION); } else { List<SAML2IDP> listSelectableOrganizations = null; if (oAttributes.contains( SAML2AuthenticationMethod.class, _sMethodId + "." + LIST_AVAILABLE_ORGANIZATIONS)) { // The selected organization was not available, select again: listSelectableOrganizations = (List<SAML2IDP>) oAttributes.get( SAML2AuthenticationMethod.class, _sMethodId + "." + LIST_AVAILABLE_ORGANIZATIONS); warnings = new Vector<Warnings>(); warnings.add(Warnings.WARNING_ORGANIZATION_UNAVAILABLE); } else { IUser oUser = session.getUser(); if (oUser != null) { // verify if user that was identified in previous authn method may use this SAML2 // authn method if (!oUser.isAuthenticationRegistered(_sMethodId)) { _eventLogger.info( new UserEventLogItem( session, request.getRemoteAddr(), UserEvent.AUTHN_METHOD_NOT_REGISTERED, this, null)); return UserEvent.AUTHN_METHOD_NOT_REGISTERED; } } listSelectableOrganizations = new Vector<SAML2IDP>(); Vector fallbackList = new Vector<String>(); Collection<String> cForcedOrganizations = getForcedIDPs(session); if (cForcedOrganizations != null && !cForcedOrganizations.isEmpty()) oAttributes.put( SAML2AuthNConstants.class, SAML2AuthNConstants.FORCED_ORGANIZATIONS, cForcedOrganizations); List<SAML2IDP> listIDPs = _organizationStorage.getAll(); for (SAML2IDP saml2IDP : listIDPs) { fallbackList.add(saml2IDP); if (cForcedOrganizations == null || cForcedOrganizations.contains(saml2IDP.getID())) { // if no forced organizations are defined or organization is in the forced // organization list: Add to select organization list. listSelectableOrganizations.add(saml2IDP); } } if (listSelectableOrganizations.isEmpty()) { // DD if no forced orgs are known locally, add all and let user decide. // Make sure proxy orgs are send with AuthN request listSelectableOrganizations = fallbackList; } } if (listSelectableOrganizations.size() == 0) { _logger.debug("No organizations available to choose from"); _eventLogger.info( new UserEventLogItem( session, request.getRemoteAddr(), UserEvent.AUTHN_METHOD_NOT_SUPPORTED, this, null)); return UserEvent.AUTHN_METHOD_NOT_SUPPORTED; } if (_oSelector == null) { organization = listSelectableOrganizations.get(0); _logger.debug("No selector configured, using: " + organization.getID()); } else { try { // Select requestor organization = _oSelector.resolve( request, response, session, listSelectableOrganizations, _sFriendlyName, warnings); } catch (OAException e) { _eventLogger.info( new UserEventLogItem( session, request.getRemoteAddr(), UserEvent.INTERNAL_ERROR, this, "selecting organization")); throw e; } } if (organization == null) { // Page is shown _eventLogger.info( new UserEventLogItem( session, request.getRemoteAddr(), UserEvent.AUTHN_METHOD_IN_PROGRESS, this, null)); return UserEvent.AUTHN_METHOD_IN_PROGRESS; } oAttributes.put( SAML2AuthenticationMethod.class, _sMethodId, SELECTED_ORGANIZATION, organization); listSelectableOrganizations.remove(organization); oAttributes.put( SAML2AuthenticationMethod.class, _sMethodId, LIST_AVAILABLE_ORGANIZATIONS, listSelectableOrganizations); } } UserEvent event = null; if (_profileWebBrowserSSO != null) { event = _profileWebBrowserSSO.process( request, response, session, organization, _htAttributeMapper); _eventLogger.info( new UserEventLogItem(session, request.getRemoteAddr(), event, this, null)); } else { _eventLogger.info( new UserEventLogItem( session, request.getRemoteAddr(), UserEvent.AUTHN_METHOD_FAILED, this, "No suitable SAML2 profile could be found for authentication")); event = UserEvent.AUTHN_METHOD_FAILED; } if (event == UserEvent.AUTHN_METHOD_FAILED && _bEnableFallback) { // fallback event = UserEvent.AUTHN_METHOD_IN_PROGRESS; oAttributes.remove( SAML2AuthenticationMethod.class, _sMethodId + "." + SELECTED_ORGANIZATION); _eventLogger.info( new UserEventLogItem( session, request.getRemoteAddr(), UserEvent.AUTHN_METHOD_IN_PROGRESS, this, "Fallback mechanism activated")); event = authenticate(request, response, session); } return event; } catch (OAException oae) { _eventLogger.info( new UserEventLogItem( session, request.getRemoteAddr(), UserEvent.AUTHN_METHOD_FAILED, this, oae.getLocalizedMessage())); throw oae; } }