From 20401a06ac4f49901755d28490ffa5895baa9589 Mon Sep 17 00:00:00 2001 From: iftachav <48707060+iftachav@users.noreply.github.com> Date: Thu, 31 Mar 2022 11:32:45 +0300 Subject: [PATCH 1/2] Create IdpChange.java --- .../src/main/java/mujina/idp/IdpChange.java | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 mujina-idp/src/main/java/mujina/idp/IdpChange.java diff --git a/mujina-idp/src/main/java/mujina/idp/IdpChange.java b/mujina-idp/src/main/java/mujina/idp/IdpChange.java new file mode 100644 index 0000000..4621707 --- /dev/null +++ b/mujina-idp/src/main/java/mujina/idp/IdpChange.java @@ -0,0 +1,139 @@ +package mujina.idp; + + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + + +import mujina.saml.SAMLAttribute; + + + +public class IdpChange { + + +public List changeRvOkta(List currentAttributeList) { +List newAttributeList = new ArrayList<>(); +//List groupList = new ArrayList<>(); +//groupList.add("Everyone"); +newAttributeList.add(new SAMLAttribute("groups", Arrays.asList("Everyone")));//In okta each user has at least one group called Everyone. +for (int i = 0; i < currentAttributeList.size(); i++) { +String name = currentAttributeList.get(i).getName(); +List value = currentAttributeList.get(i).getValues(); +if(name.contains("givenName")) +newAttributeList.add(new SAMLAttribute("firstName", value)); +else if(name.contains("sn")) +newAttributeList.add(new SAMLAttribute("lastName", value)); +else if(name.contains("uid")) +newAttributeList.add(new SAMLAttribute("userId", value)); +//else if(name.contains("isMemberOf")) +//groupList.add(value.toString()); +//temp.add(new SAMLAttribute("groups", value)); +} +//temp.add(new SAMLAttribute("groups", groupList)); +return newAttributeList; +} + +public List changeRvAdfs(List currentAttributeList) { +List newAttributeList = new ArrayList<>(); +//List groupList = new ArrayList<>(); +//groupList.add("default Group"); +newAttributeList.add(new SAMLAttribute("http://schemas.xmlsoap.org/claims/Group", Arrays.asList("default Group"))); +for (int i = 0; i < currentAttributeList.size(); i++) { +String name = currentAttributeList.get(i).getName(); +List value = currentAttributeList.get(i).getValues(); +if(name.contains("givenName")){ +newAttributeList.add(new SAMLAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", value)); +newAttributeList.add(new SAMLAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", value)); +} +else if(name.contains("sn")) +newAttributeList.add(new SAMLAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname", value)); +//else if(name.contains("isMemberOf")) +//groupList.add(value.toString()); +//temp.add(new SAMLAttribute("http://schemas.xmlsoap.org/claims/Group", value)); +else if(name.contains("uid")) +newAttributeList.add(new SAMLAttribute("http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid", value)); +} +//temp.add(new SAMLAttribute("http://schemas.xmlsoap.org/claims/Group", groupList)); +newAttributeList.add(new SAMLAttribute("http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid", Arrays.asList("S-1-5-21-1752647966-813121237-1802144934-444"))); +return newAttributeList; +} + + +public List changeRvAzure(List currentAttributeList) { +List newAttributeList = new ArrayList<>(); +for (int i = 0; i < currentAttributeList.size(); i++) { +String name = currentAttributeList.get(i).getName(); +List value = currentAttributeList.get(i).getValues(); +if(name.contains("sn")) +newAttributeList.add(new SAMLAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname", value)); +else if(name.contains("uid")){ +newAttributeList.add(new SAMLAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", value)); +newAttributeList.add(new SAMLAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", value)); +} +else if(name.contains("isMemberOf")) +newAttributeList.add(new SAMLAttribute("groups", value)); +else if(name.contains("displayName")) +newAttributeList.add(new SAMLAttribute("http://schemas.microsoft.com/identity/claims/displayname", value)); +else if(name.contains("givenName")) +newAttributeList.add(new SAMLAttribute("http://schemas.microsoft.com/identity/claims/givenname", value)); + +} +newAttributeList.add(new SAMLAttribute("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", Arrays.asList("admin"))); +newAttributeList.add(new SAMLAttribute("http://schemas.microsoft.com/ws/2008/06/identity/claims/groups", Arrays.asList("b4e61a24-a485-4363-b6b3-de0247d7db7c", "5ee7c6ef-fbca-40cb-a0b2-2f831cba1399", "f3a3c151-bcf2-4c18-a2f0-7284eb48d86d"))); +newAttributeList.add(new SAMLAttribute("http://schemas.microsoft.com/identity/claims/tenantid", Arrays.asList("tenantid default"))); +newAttributeList.add(new SAMLAttribute("http://schemas.microsoft.com/identity/claims/objectidentifier", Arrays.asList("objectidentifier default"))); +newAttributeList.add(new SAMLAttribute("http://schemas.microsoft.com/identity/claims/identityprovider", Arrays.asList("identityprovider default"))); +newAttributeList.add(new SAMLAttribute("http://schemas.microsoft.com/identity/claims/authnmethodsreferences", Arrays.asList("authnmethodsreferences default"))); +return newAttributeList; +} + + +public List changeRvOneLogin(List currentAttributeList) { +List newAttributeList = new ArrayList<>(); +newAttributeList.add(new SAMLAttribute("groups", Arrays.asList("default group")));//In onelogin groups can be empty. +for (int i = 0; i < currentAttributeList.size(); i++) { +String name = currentAttributeList.get(i).getName(); +List value = currentAttributeList.get(i).getValues(); +if(name.contains("givenName")) +newAttributeList.add(new SAMLAttribute("firstName", value)); +else if(name.contains("sn")) +newAttributeList.add(new SAMLAttribute("lastName", value)); +else if(name.contains("uid")){ +newAttributeList.add(new SAMLAttribute("userID", value)); +newAttributeList.add(new SAMLAttribute("email", value)); +} + +else if(name.contains("isMemberOf")) +newAttributeList.add(new SAMLAttribute("groups", value)); +} +return newAttributeList; +} + + + +public List changeRvPing(List currentAttributeList) { +List newAttributeList = new ArrayList<>(); +for (int i = 0; i < currentAttributeList.size(); i++) { +String name = currentAttributeList.get(i).getName(); +List value = currentAttributeList.get(i).getValues(); +if(name.contains("givenName")) +newAttributeList.add(new SAMLAttribute("firstName", value)); +else if(name.contains("sn")) +newAttributeList.add(new SAMLAttribute("lastName", value)); +else if(name.contains("uid")) +newAttributeList.add(new SAMLAttribute("email", value)); + +else if(name.contains("isMemberOf")) { +for (int j = 0; j < value.size(); j++)//In Ping all groups has @directory postfix. +value.set(j, value.get(j)+"@directory"); +newAttributeList.add(new SAMLAttribute("memberOf", value)); +} +} +return newAttributeList; +} + +} From 772554a41a017e5bdc2e3e6938da5a8604125ffd Mon Sep 17 00:00:00 2001 From: iftachav <48707060+iftachav@users.noreply.github.com> Date: Thu, 31 Mar 2022 11:33:27 +0300 Subject: [PATCH 2/2] Update SsoController.java --- .../main/java/mujina/idp/SsoController.java | 233 ++++++++++++------ 1 file changed, 155 insertions(+), 78 deletions(-) diff --git a/mujina-idp/src/main/java/mujina/idp/SsoController.java b/mujina-idp/src/main/java/mujina/idp/SsoController.java index a8c2383..a30041d 100644 --- a/mujina-idp/src/main/java/mujina/idp/SsoController.java +++ b/mujina-idp/src/main/java/mujina/idp/SsoController.java @@ -1,7 +1,12 @@ package mujina.idp; + + import mujina.api.IdpConfiguration; import mujina.saml.SAMLAttribute; + + + import mujina.saml.SAMLPrincipal; import org.opensaml.common.binding.SAMLMessageContext; import org.opensaml.saml2.core.AuthnRequest; @@ -19,8 +24,11 @@ import org.springframework.stereotype.Controller; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; + + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -31,89 +39,158 @@ import java.util.Map; import java.util.Optional; + + import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; + + @Controller public class SsoController { - @Autowired - private SAMLMessageHandler samlMessageHandler; - - @Autowired - private IdpConfiguration idpConfiguration; - - @GetMapping("/SingleSignOnService") - public void singleSignOnServiceGet(HttpServletRequest request, HttpServletResponse response, Authentication authentication) - throws IOException, MarshallingException, SignatureException, MessageEncodingException, ValidationException, SecurityException, MessageDecodingException, MetadataProviderException, ServletException { - doSSO(request, response, authentication, false); - } - - @PostMapping("/SingleSignOnService") - public void singleSignOnServicePost(HttpServletRequest request, HttpServletResponse response, Authentication authentication) - throws IOException, MarshallingException, SignatureException, MessageEncodingException, ValidationException, SecurityException, MessageDecodingException, MetadataProviderException, ServletException { - doSSO(request, response, authentication, true); - } - - @SuppressWarnings("unchecked") - private void doSSO(HttpServletRequest request, HttpServletResponse response, Authentication authentication, boolean postRequest) throws ValidationException, SecurityException, MessageDecodingException, MarshallingException, SignatureException, MessageEncodingException, MetadataProviderException, IOException, ServletException { - SAMLMessageContext messageContext = samlMessageHandler.extractSAMLMessageContext(request, response, postRequest); - AuthnRequest authnRequest = (AuthnRequest) messageContext.getInboundSAMLMessage(); - - String assertionConsumerServiceURL = idpConfiguration.getAcsEndpoint() != null ? idpConfiguration.getAcsEndpoint() : authnRequest.getAssertionConsumerServiceURL(); - List attributes = attributes(authentication); - - SAMLPrincipal principal = new SAMLPrincipal( - authentication.getName(), - attributes.stream() - .filter(attr -> "urn:oasis:names:tc:SAML:1.1:nameid-format".equals(attr.getName())) - .findFirst().map(attr -> attr.getValue()).orElse(NameIDType.UNSPECIFIED), - attributes, - authnRequest.getIssuer().getValue(), - authnRequest.getID(), - assertionConsumerServiceURL, - messageContext.getRelayState()); - - samlMessageHandler.sendAuthnResponse(principal, response); - } - - @SuppressWarnings("unchecked") - private List attributes(Authentication authentication) { - String uid = authentication.getName(); - Map> result = new HashMap<>(idpConfiguration.getAttributes()); - - - Optional>> optionalMap = idpConfiguration.getUsers().stream() - .filter(user -> user.getPrincipal().equals(uid)) - .findAny() - .map(FederatedUserAuthenticationToken::getAttributes); - optionalMap.ifPresent(result::putAll); - - //See SAMLAttributeAuthenticationFilter#setDetails - Map parameterMap = (Map) authentication.getDetails(); - parameterMap.forEach((key, values) -> { - result.put(key, Arrays.asList(values)); - }); - - //Check if the user wants to be persisted - if (parameterMap.containsKey("persist-me") && "on".equalsIgnoreCase(parameterMap.get("persist-me")[0])) { - result.remove("persist-me"); - FederatedUserAuthenticationToken token = new FederatedUserAuthenticationToken( - uid, - authentication.getCredentials(), - Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))); - token.setAttributes(result); - idpConfiguration.getUsers().removeIf(existingUser -> existingUser.getPrincipal().equals(uid)); - idpConfiguration.getUsers().add(token); - } - - //Provide the ability to limit the list attributes returned to the SP - return result.entrySet().stream() - .filter(entry -> !entry.getValue().stream().allMatch(StringUtils::isEmpty)) - .map(entry -> entry.getKey().equals("urn:mace:dir:attribute-def:uid") ? - new SAMLAttribute(entry.getKey(), singletonList(uid)) : - new SAMLAttribute(entry.getKey(), entry.getValue())) - .collect(toList()); - } +public final String DEFAULT_TYPE="mujina"; +public String[] idpArray= {"adfs", "okta", "onelogin", "ping", "azure"}; + + + +@Autowired +private SAMLMessageHandler samlMessageHandler; + + + +@Autowired +private IdpConfiguration idpConfiguration; + + + +@GetMapping("/SingleSignOnService") +public void singleSignOnServiceGet(HttpServletRequest request, HttpServletResponse response, Authentication authentication) +throws IOException, MarshallingException, SignatureException, MessageEncodingException, ValidationException, SecurityException, MessageDecodingException, MetadataProviderException, ServletException { +doSSO(request, response, authentication, false, DEFAULT_TYPE); +} + + + + +@PostMapping("/SingleSignOnService") +public void singleSignOnServicePost(HttpServletRequest request, HttpServletResponse response, Authentication authentication) +throws IOException, MarshallingException, SignatureException, MessageEncodingException, ValidationException, SecurityException, MessageDecodingException, MetadataProviderException, ServletException { +doSSO(request, response, authentication, true, DEFAULT_TYPE); +} + + + + +@GetMapping("/SingleSignOnService/{optionalType}") +public void singleSignOnServiceGet(@PathVariable Optional optionalType,HttpServletRequest request, HttpServletResponse response, Authentication authentication) +throws IOException, MarshallingException, SignatureException, MessageEncodingException, ValidationException, SecurityException, MessageDecodingException, MetadataProviderException, ServletException { +if (optionalType.isPresent()) { +doSSO(request, response, authentication, false, optionalType.get()); +} else +doSSO(request, response, authentication, false, DEFAULT_TYPE); +} + + +@PostMapping("/SingleSignOnService/{optionalType}") +public void singleSignOnServicePost(@PathVariable Optional optionalType,HttpServletRequest request, HttpServletResponse response, Authentication authentication) +throws IOException, MarshallingException, SignatureException, MessageEncodingException, ValidationException, SecurityException, MessageDecodingException, MetadataProviderException, ServletException { +if (optionalType.isPresent()) { +doSSO(request, response, authentication, true, optionalType.get()); +} else +doSSO(request, response, authentication, true, DEFAULT_TYPE); +} + + + +@SuppressWarnings("unchecked") +private void doSSO(HttpServletRequest request, HttpServletResponse response, Authentication authentication, boolean postRequest, String optionalIdpType) throws ValidationException, SecurityException, MessageDecodingException, MarshallingException, SignatureException, MessageEncodingException, MetadataProviderException, IOException, ServletException { +SAMLMessageContext messageContext = samlMessageHandler.extractSAMLMessageContext(request, response, postRequest); +AuthnRequest authnRequest = (AuthnRequest) messageContext.getInboundSAMLMessage(); +String assertionConsumerServiceURL = idpConfiguration.getAcsEndpoint() != null ? idpConfiguration.getAcsEndpoint() : authnRequest.getAssertionConsumerServiceURL(); + +List attributes = attributes(authentication, optionalIdpType); +SAMLPrincipal principal = new SAMLPrincipal( +authentication.getName(), +attributes.stream() +.filter(attr -> "urn:oasis:names:tc:SAML:1.1:nameid-format".equals(attr.getName())) +.findFirst().map(attr -> attr.getValue()).orElse(NameIDType.EMAIL), +attributes, +authnRequest.getIssuer().getValue(), +authnRequest.getID(), +assertionConsumerServiceURL, +messageContext.getRelayState()); + + + +samlMessageHandler.sendAuthnResponse(principal, response); +} + + + +@SuppressWarnings("unchecked") +private List attributes(Authentication authentication, String idpType) { +String uid = authentication.getName(); +Map> result = new HashMap<>(idpConfiguration.getAttributes()); + + + +Optional>> optionalMap = idpConfiguration.getUsers().stream() +.filter(user -> user.getPrincipal().equals(uid)) +.findAny() +.map(FederatedUserAuthenticationToken::getAttributes); +optionalMap.ifPresent(result::putAll); + + + +//See SAMLAttributeAuthenticationFilter#setDetails +Map parameterMap = (Map) authentication.getDetails(); +parameterMap.forEach((key, values) -> { +result.put(key, Arrays.asList(values)); +}); + + + +//Check if the user wants to be persisted +if (parameterMap.containsKey("persist-me") && "on".equalsIgnoreCase(parameterMap.get("persist-me")[0])) { +result.remove("persist-me"); +FederatedUserAuthenticationToken token = new FederatedUserAuthenticationToken( +uid, +authentication.getCredentials(), +Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))); +token.setAttributes(result); +idpConfiguration.getUsers().removeIf(existingUser -> existingUser.getPrincipal().equals(uid)); +idpConfiguration.getUsers().add(token); +} +//Provide the ability to limit the list attributes returned to the SP +List attributeList = result.entrySet().stream() +.filter(entry -> !entry.getValue().stream().allMatch(StringUtils::isEmpty)) +.map(entry -> entry.getKey().equals("urn:mace:dir:attribute-def:uid") ? +new SAMLAttribute(entry.getKey(), singletonList(uid)) : +new SAMLAttribute(entry.getKey(), entry.getValue())) +.collect(toList()); + +IdpChange idpChange = new IdpChange(); + +switch(idpType) { +case "okta": +attributeList = idpChange.changeRvOkta(attributeList); +break; +case "adfs": +attributeList = idpChange.changeRvAdfs(attributeList); +break; +case "azure": +attributeList = idpChange.changeRvAzure(attributeList); +break; +case "onelogin": +attributeList = idpChange.changeRvOneLogin(attributeList); +break; +case "ping": +attributeList = idpChange.changeRvPing(attributeList); +break; +} + +return attributeList; +} }