Giter Site home page Giter Site logo

identity-inbound-provisioning-scim2's Introduction

Welcome to the WSO2 Identity Server (IS) identity-inbound-provisioning-scim2.

WSO2 IS is one of the best Identity Servers, which enables you to offload your identity and user entitlement management burden totally from your application. It comes with many features, supports many industry standards and most importantly it allows you to extent it according to your security requirements. This repo contains Authenticators written to work with different third party systems.

With WSO2 IS, there are lot of provisioning capabilities available. There are 3 major concepts as Inbound, outbound provisioning and Just-In-Time provisioning. Inbound provisioning means , provisioning users and groups from an external system to IS. Outbound provisioning means , provisioning users from IS to other external systems. JIT provisioning means , once a user tries to login from an external IDP, a user can be created on the fly in IS with JIT. Repos under this account holds such components invlove in communicating with external systems.

Building from the source

If you want to build identity-inbound-provisioning-scim2 from the source code:

  1. Install Java 11 (or Java 17)
  2. Install Apache Maven 3.x.x (https://maven.apache.org/download.cgi#)
  3. Get a clone or download the source from this repository (https://github.com/wso2-extensions/identity-inbound-provisioning-scim2)
  4. Run the Maven command mvn clean install from the identity-inbound-provisioning-scim2 directory.

identity-inbound-provisioning-scim2's People

Contributors

anuradhask avatar ashendes avatar ashensw avatar bhagyasakalanka avatar chanikaruchini avatar connector-store-rw-bot avatar dewnimw avatar dmhp avatar emswbandara avatar gangani avatar gdrdabarera avatar isurad avatar janakamarasena avatar jkaushalya avatar kayathiri4 avatar madurangasiriwardena avatar malithie avatar nilasini avatar pasinduyeshan avatar piraveena avatar piyarathnalakmali avatar sarubi avatar senthalan avatar shanchathusanda93 avatar shashimalcse avatar somindatommy avatar thanujalk avatar tharindu-b-hewage avatar vindulamj avatar wso2-jenkins-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

identity-inbound-provisioning-scim2's Issues

Slowness in Update Group Patch operation of SCIM2 API

Description:

Noticed a slowness when using Update Group Patch operation of SCIM API as explained in the below documentation.

https://docs.wso2.com/display/IS570/apidocs/SCIM2-endpoints/#!/operations#GroupsEndpoint#patchGroup

Suggested Labels:

SCIM
Suggested Assignees:

Affected Product Version:
wso2is-km-5.7.0

OS, DB, other environment details and versions:
Local H2 DB

Steps to reproduce:

  1. Configure JDBCUserStoreManager with WSO2 IS and enable SCIM operations (wso2is-km-5.7.0)
  2. Create a role (i.e : role1)
  3. Add a large number of users to the user store (i.e: 2000 users) and assign those users to the role
  4. Now create a new user and try to assign that user to the same role using the SCIM API like bellow

curl -v -k --user admin:admin -X PATCH -d '{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],"Operations":[{"op":"add","value":{"members":[{"display": "abc","$ref":"https://localhost:9443/scim2/Users/b3b49f38-4249-4d98-90e1-e744fa1e9b41","value": "b3b49f38-4249-4d98-90e1-e744fa1e9b41"}]}}]}' --header "Content-Type:application/json" https://localhost:9443/scim2/Groups/22232155-0875-4f48-b15d-11d99675b807

  1. It took around 5 minutes to run the above operation when there are 2000 users already there in the given role

Complex attributes in custom schema does not handle properly

Affected Product Version:
IS 5.4.0

Steps to reproduce:
Define a complex custom attribute
{"WSO2":{"Private":{"Email":"[email protected]","id":"9876-9876-9876"},"Work":{"workEmail":"[email protected]","team":"IAM","workid":"9495-2453-7377"}}
If you define the claim mappings properly, It will add the user with all the attributes.

But when we try to get the user it will only return a part of it.
{"WSO2":{"Work":{"workEmail":"[email protected]"}}

Paginated User search returns an incorrect totalResults when applying a filter

Description:
There is an wrong behaviour with the SCIM2 User paginated search whenever you apply a filter to the search that causes totalResults pagination metadata to return an incorrect value: instead of reporting the actual total results count, it just reports your current result size both in the itemsPerPage and totalResults parameters.

When you call POST /Users/.search or GET /Users, SCIMUserManager.listUsersWithGET() method is internally called.

    @Override
    public List<Object> listUsersWithPost(SearchRequest searchRequest, Map<String, Boolean> requiredAttributes)
            throws CharonException, NotImplementedException, BadRequestException {

        return listUsersWithGET(searchRequest.getFilter(), (Integer)searchRequest.getStartIndex(),
                (Integer)searchRequest.getCount(), searchRequest.getSortBy(), searchRequest.getSortOder(),
                searchRequest.getDomainName(), requiredAttributes);
    }

This method calls listUsers() when there's no informed filter, and filterUsers() when there's one.

    @Override
    public List<Object> listUsersWithGET(Node rootNode, Integer startIndex, Integer count, String sortBy,
                                         String sortOrder, String domainName, Map<String, Boolean> requiredAttributes)
            throws CharonException, NotImplementedException {

        // Validate NULL value for startIndex.
        startIndex = handleStartIndexEqualsNULL(startIndex);
        if (sortBy != null || sortOrder != null) {
            throw new NotImplementedException("Sorting is not supported");
        } else if (count != null && count == 0) {
            return Collections.emptyList();
        } else if (rootNode != null) {
            return filterUsers(rootNode, requiredAttributes, startIndex, count, sortBy, sortOrder, domainName);
        } else {
            return listUsers(requiredAttributes, startIndex, count, sortBy, sortOrder, domainName);
        }
    }

Internally, listUsers() calculates total count and then sets it in response (List[0]):

            //...

            if (canPaginate(offset, limit)) {
                coreUsers = listUsernamesAcrossAllDomains(offset, limit, sortBy, sortOrder);

                String[] userStoreDomainNames = getDomainNames();
                boolean canCountTotalUserCount = canCountTotalUserCount(userStoreDomainNames);
                if (canCountTotalUserCount) {
                    for (String userStoreDomainName : userStoreDomainNames) {
                        totalUsers += getTotalUsers(userStoreDomainName);
                    }
                }
            }

            //...
            List<Object> scimUsers = getUserDetails(coreUsers, requiredAttributes);
            if (totalUsers != 0) {
                users.set(0, Math.toIntExact(totalUsers)); // Set total number of results to 0th index.
            } else {
                users.set(0, scimUsers.size());
            }
            users.addAll(scimUsers); // Set user details from index 1.

However, when filterUsers() is called, whether it calls filterUsersBySingleAttribute() or getMultiAttributeFilteredUsers() it is using the current search result size as a total result.

In the case of filterUsersBySingleAttribute(), a getDetailedUsers() method is called after retrieving users:

    private List<Object> filterUsersBySingleAttribute(ExpressionNode node, Map<String, Boolean> requiredAttributes,
                                                      int offset, int limit, String sortBy, String sortOrder,
                                                      String domainName) throws CharonException {

        Set<org.wso2.carbon.user.core.common.User> users;

        if (log.isDebugEnabled()) {
            log.debug(String.format("Listing users by filter: %s %s %s", node.getAttributeValue(), node.getOperation(),
                    node.getValue()));
        }
        // Check whether the filter operation is supported by the users endpoint.
        if (isFilteringNotSupported(node.getOperation())) {
            String errorMessage =
                    "Filter operation: " + node.getOperation() + " is not supported for filtering in users endpoint.";
            throw new CharonException(errorMessage);
        }
        domainName = resolveDomainName(domainName, node);
        try {
            // Check which APIs should the filter needs to follow.
            if (isUseLegacyAPIs(limit)) {
                users = filterUsersUsingLegacyAPIs(node, limit, offset, domainName);
            } else {
                users = filterUsers(node, offset, limit, sortBy, sortOrder, domainName);
            }
        } catch (NotImplementedException e) {
            String errorMessage = String.format("System does not support filter operator: %s", node.getOperation());
            throw new CharonException(errorMessage, e);
        }

        return getDetailedUsers(users, requiredAttributes);
    }
    private List<Object> getDetailedUsers(Set<org.wso2.carbon.user.core.common.User> coreUsers,
                                          Map<String, Boolean> requiredAttributes)
            throws CharonException {

        List<Object> filteredUsers = new ArrayList<>();
        // 0th index is to store total number of results.
        filteredUsers.add(0);

        // Set total number of filtered results.
        filteredUsers.set(0, coreUsers.size());

        // Get details of the finalized user list.
        filteredUsers.addAll(getFilteredUserDetails(coreUsers, requiredAttributes));
        return filteredUsers;
    }

...and it sets search size as total result.

On the other hand, getMultiAttributeFilteredUsers() sets directly total results (List[0]) as users size:

    private List<Object> getMultiAttributeFilteredUsers(Node node, Map<String, Boolean> requiredAttributes, int offset,
                                                        int limit, String sortBy, String sortOrder, String domainName)
            throws CharonException {

        List<Object> filteredUsers = new ArrayList<>();
        // 0th index is to store total number of results.
        filteredUsers.add(0);
        Set<org.wso2.carbon.user.core.common.User> users;
        // Handle pagination.
        if (limit > 0) {
            users = getFilteredUsersFromMultiAttributeFiltering(node, offset, limit, sortBy, sortOrder, domainName);
            filteredUsers.set(0, users.size());
            filteredUsers.addAll(getFilteredUserDetails(users, requiredAttributes));
        } else {
            int maxLimit = getMaxLimit(domainName);
            if (StringUtils.isNotEmpty(domainName)) {
                users = getFilteredUsersFromMultiAttributeFiltering(node, offset, maxLimit, sortBy,
                        sortOrder, domainName);
                filteredUsers.set(0, users.size());
                filteredUsers.addAll(getFilteredUserDetails(users, requiredAttributes));
            } else {
                int totalUserCount = 0;
                // If pagination and domain name are not given, then perform filtering on all available user stores.
                while (carbonUM != null) {
                    // If carbonUM is not an instance of Abstract User Store Manger we can't get the domain name.
                    if (carbonUM instanceof AbstractUserStoreManager) {
                        domainName = carbonUM.getRealmConfiguration().getUserStoreProperty("DomainName");
                        users = getFilteredUsersFromMultiAttributeFiltering(node, offset, maxLimit,
                                sortBy, sortOrder, domainName);
                        totalUserCount += users.size();
                        filteredUsers.addAll(getFilteredUserDetails(users, requiredAttributes));
                    }
                    carbonUM = (AbstractUserStoreManager) carbonUM.getSecondaryUserStoreManager();
                }
                //set the total results
                filteredUsers.set(0, totalUserCount);
            }
        }
        return filteredUsers;
    }

So, when we make the following request:

{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:SearchRequest"
  ],
  "attributes": [
    "name",
    "userName",
    "emails",
    "dateOfBirth",
    "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
    "groups"
  ],
  "filter": "groups eq roleName",
  "domain": "PRIMARY",
  "startIndex": 1,
  "count": 2
}

It gives us a result like this:

{
    "totalResults": 2,
    "startIndex": 1,
    "itemsPerPage": 2,
    //...
}

When the actual total results is 3, as seen in the example below (where a count of 10 is requested):

{
    "totalResults": 3,
    "startIndex": 1,
    "itemsPerPage": 3,
    //...
}

Suggested Labels:

Suggested Assignees:

Affected Product Version:
From 5.10.0 to latest (master)

OS, DB, other environment details and versions:
Windows, H2, WSO2IS-KM-5.10.0

Steps to reproduce:

  • Make sure you have more than 2 registered users that will match search criteria.
  • Make a POST /Users/.search request with the following information (i.e: with a given filter and a count size equal to 2):
{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:SearchRequest"
  ],
  "attributes": [
    "name",
    "userName",
    "emails",
    "dateOfBirth",
    "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
    "groups"
  ],
  "filter": "groups eq roleName",
  "domain": "PRIMARY",
  "startIndex": 1,
  "count": 2
}

And it will return a totalResults count with the same value as the itemsPerPage attribute:

{
    "totalResults": 2,
    "startIndex": 1,
    "itemsPerPage": 2,
    //...
}

Related Issues:

Hardcoded policy errors

Description:
Policy errors list is hardcoded in org.wso2.carbon.identity.scim2.common.impl.SCIMUserManager.handleErrorsOnUserNameAndPasswordPolicy(Throwable e)

Natively all username and password code are not managed.
Developers can also add their own custom policies and errors code.

If an unknown error code is received a generic CharonException is thrown and a 500 is returned to the caller.
{"schemas":["urn:ietf:params:scim:api:messages:2.0:Error"],"detail":"Error while updating attributes of user: test","status":"500"}
But in those cases it's a user mistake so a 4XX must be returned and an explicit error message must be sent back depending of the policy.

Suggestion:
Create an error code range convention for user errors or a specific class exception to catch.

Suggested Labels:
BUG

Affected Product Version:
All

OS, DB, other environment details and versions:
N/A

Steps to reproduce:
Create your own password policy and try a bad pattern.

Related Issues:
N/A

Update scim2 feature

I made changes in the src.
How do I update my wso2is 5.7.0 with the modified scim2 ?

Change the scim2 documentation URI

Description:
When SCIM 2.0 REST APIs doc for IS5.9.0 is ready then change the below key.

scim2.documentation_uri

Suggested Labels:
5.9.0
Configuration

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.