org.apache.syncope.fit.core.reference.AuthenticationITCase.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.syncope.fit.core.reference.AuthenticationITCase.java

Source

/*
 * 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.syncope.fit.core.reference;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.security.AccessControlException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.client.lib.SyncopeClient;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.mod.StatusMod;
import org.apache.syncope.common.lib.mod.UserMod;
import org.apache.syncope.common.lib.to.BulkActionResult;
import org.apache.syncope.common.lib.to.MembershipTO;
import org.apache.syncope.common.lib.to.PagedResult;
import org.apache.syncope.common.lib.to.PlainSchemaTO;
import org.apache.syncope.common.lib.to.RoleTO;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.to.WorkflowFormPropertyTO;
import org.apache.syncope.common.lib.to.WorkflowFormTO;
import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.common.lib.types.CipherAlgorithm;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.Entitlement;
import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
import org.apache.syncope.common.lib.types.SchemaType;
import org.apache.syncope.common.lib.wrap.ResourceKey;
import org.apache.syncope.common.rest.api.CollectionWrapper;
import org.apache.syncope.common.rest.api.service.SchemaService;
import org.apache.syncope.common.rest.api.service.UserService;
import org.apache.syncope.core.misc.security.Encryptor;
import org.junit.Assume;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.springframework.jdbc.core.JdbcTemplate;

@FixMethodOrder(MethodSorters.JVM)
public class AuthenticationITCase extends AbstractITCase {

    private int getFailedLogins(final UserService userService, final long userId) {
        UserTO readUserTO = userService.read(userId);
        assertNotNull(readUserTO);
        assertNotNull(readUserTO.getFailedLogins());
        return readUserTO.getFailedLogins();
    }

    private void assertReadFails(final SyncopeClient client) {
        try {
            client.self();
            fail("access should not work");
        } catch (Exception e) {
            assertNotNull(e);
        }
    }

    @Test
    public void testReadEntitlements() {
        // 1. as anonymous (not allowed)
        try {
            clientFactory.createAnonymous().self();
            fail();
        } catch (AccessControlException e) {
            assertNotNull(e);
        }

        // 2. as authenticated anonymous (used by admin console)
        Pair<Map<String, Set<String>>, UserTO> self = clientFactory.create(ANONYMOUS_UNAME, ANONYMOUS_KEY).self();
        assertEquals(1, self.getKey().size());
        assertTrue(self.getKey().keySet().contains(Entitlement.ANONYMOUS));
        assertEquals(ANONYMOUS_UNAME, self.getValue().getUsername());

        // 3. as admin
        self = adminClient.self();
        assertEquals(Entitlement.values().size() - 1, self.getKey().size());
        assertFalse(self.getKey().keySet().contains(Entitlement.ANONYMOUS));
        assertEquals(ADMIN_UNAME, self.getValue().getUsername());

        // 4. as user
        self = clientFactory.create("bellini", ADMIN_PWD).self();
        assertFalse(self.getKey().isEmpty());
        assertFalse(self.getKey().keySet().contains(Entitlement.ANONYMOUS));
        assertEquals("bellini", self.getValue().getUsername());
    }

    @Test
    public void testUserSchemaAuthorization() {
        // 0. create a role that can only read schemas
        RoleTO roleTO = new RoleTO();
        roleTO.setName("authRole" + getUUIDString());
        roleTO.getEntitlements().add(Entitlement.SCHEMA_READ);
        roleTO.getRealms().add("/odd");

        roleTO = createRole(roleTO);
        assertNotNull(roleTO);

        String schemaName = "authTestSchema" + getUUIDString();

        // 1. create a schema (as admin)
        PlainSchemaTO schemaTO = new PlainSchemaTO();
        schemaTO.setKey(schemaName);
        schemaTO.setMandatoryCondition("false");
        schemaTO.setType(AttrSchemaType.String);

        PlainSchemaTO newPlainSchemaTO = createSchema(SchemaType.PLAIN, schemaTO);
        assertEquals(schemaTO, newPlainSchemaTO);

        // 2. create an user with the role created above (as admin)
        UserTO userTO = UserITCase.getUniqueSampleTO("auth@test.org");
        userTO.getRoles().add(roleTO.getKey());

        userTO = createUser(userTO);
        assertNotNull(userTO);

        // 3. read the schema created above (as admin) - success
        schemaTO = schemaService.read(SchemaType.PLAIN, schemaName);
        assertNotNull(schemaTO);

        // 4. read the schema created above (as user) - success
        SchemaService schemaService2 = clientFactory.create(userTO.getUsername(), "password123")
                .getService(SchemaService.class);
        schemaTO = schemaService2.read(SchemaType.PLAIN, schemaName);
        assertNotNull(schemaTO);

        // 5. update the schema create above (as user) - failure
        try {
            schemaService2.update(SchemaType.PLAIN, schemaTO);
            fail("Schemaupdate as user should not work");
        } catch (AccessControlException e) {
            // CXF Service will throw this exception
            assertNotNull(e);
        }

        assertEquals(0, getFailedLogins(userService, userTO.getKey()));
    }

    @Test
    public void testUserRead() {
        UserTO userTO = UserITCase.getUniqueSampleTO("testuserread@test.org");
        userTO.getRoles().add(2L);

        userTO = createUser(userTO);
        assertNotNull(userTO);

        UserService userService2 = clientFactory.create(userTO.getUsername(), "password123")
                .getService(UserService.class);

        UserTO readUserTO = userService2.read(1L);
        assertNotNull(readUserTO);

        UserService userService3 = clientFactory.create("puccini", ADMIN_PWD).getService(UserService.class);

        try {
            userService3.read(3L);
            fail();
        } catch (SyncopeClientException e) {
            assertNotNull(e);
            assertEquals(ClientExceptionType.Unauthorized, e.getType());
        }
    }

    @Test
    public void testUserSearch() {
        UserTO userTO = UserITCase.getUniqueSampleTO("testusersearch@test.org");
        userTO.getRoles().add(1L);

        userTO = createUser(userTO);
        assertNotNull(userTO);

        // 1. user assigned to role 1, with search entitlement on realms /odd and /even: won't find anything with 
        // root realm
        UserService userService2 = clientFactory.create(userTO.getUsername(), "password123")
                .getService(UserService.class);

        PagedResult<UserTO> matchedUsers = userService2
                .search(SyncopeClient.getAnySearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM)
                        .fiql(SyncopeClient.getUserSearchConditionBuilder().isNotNull("key").query()).build());
        assertNotNull(matchedUsers);
        assertFalse(matchedUsers.getResult().isEmpty());
        Set<Long> matchedUserKeys = CollectionUtils.collect(matchedUsers.getResult(),
                new Transformer<UserTO, Long>() {

                    @Override
                    public Long transform(final UserTO input) {
                        return input.getKey();
                    }
                }, new HashSet<Long>());
        assertTrue(matchedUserKeys.contains(1L));
        assertFalse(matchedUserKeys.contains(2L));
        assertFalse(matchedUserKeys.contains(5L));

        // 2. user assigned to role 4, with search entitlement on realm /even/two
        UserService userService3 = clientFactory.create("puccini", ADMIN_PWD).getService(UserService.class);

        matchedUsers = userService3.search(SyncopeClient.getAnySearchQueryBuilder().realm("/even/two")
                .fiql(SyncopeClient.getUserSearchConditionBuilder().isNotNull("loginDate").query()).build());
        assertNotNull(matchedUsers);
        assertTrue(CollectionUtils.matchesAll(matchedUsers.getResult(), new Predicate<UserTO>() {

            @Override
            public boolean evaluate(final UserTO matched) {
                return "/even/two".equals(matched.getRealm());
            }
        }));
    }

    @Test
    public void checkFailedLogins() {
        UserTO userTO = UserITCase.getUniqueSampleTO("checkFailedLogin@syncope.apache.org");
        userTO.getRoles().add(2L);

        userTO = createUser(userTO);
        assertNotNull(userTO);
        long userId = userTO.getKey();

        UserService userService2 = clientFactory.create(userTO.getUsername(), "password123")
                .getService(UserService.class);
        assertEquals(0, getFailedLogins(userService2, userId));

        // authentications failed ...
        SyncopeClient badPwdClient = clientFactory.create(userTO.getUsername(), "wrongpwd1");
        assertReadFails(badPwdClient);
        assertReadFails(badPwdClient);

        assertEquals(2, getFailedLogins(userService, userId));

        UserService userService4 = clientFactory.create(userTO.getUsername(), "password123")
                .getService(UserService.class);
        assertEquals(0, getFailedLogins(userService4, userId));
    }

    @Test
    public void checkUserSuspension() {
        UserTO userTO = UserITCase.getUniqueSampleTO("checkSuspension@syncope.apache.org");
        userTO.setRealm("/odd");
        userTO.getRoles().add(2L);

        userTO = createUser(userTO);
        long userId = userTO.getKey();
        assertNotNull(userTO);

        assertEquals(0, getFailedLogins(userService, userId));

        // authentications failed ...
        SyncopeClient badPwdClient = clientFactory.create(userTO.getUsername(), "wrongpwd1");
        assertReadFails(badPwdClient);
        assertReadFails(badPwdClient);
        assertReadFails(badPwdClient);

        assertEquals(3, getFailedLogins(userService, userId));

        // last authentication before suspension
        assertReadFails(badPwdClient);

        userTO = userService.read(userTO.getKey());
        assertNotNull(userTO);
        assertNotNull(userTO.getFailedLogins());
        assertEquals(3, userTO.getFailedLogins(), 0);
        assertEquals("suspended", userTO.getStatus());

        // Access with correct credentials should fail as user is suspended
        SyncopeClient goodPwdClient = clientFactory.create(userTO.getUsername(), "password123");
        assertReadFails(goodPwdClient);

        StatusMod reactivate = new StatusMod();
        reactivate.setType(StatusMod.ModType.REACTIVATE);
        userTO = userService.status(userTO.getKey(), reactivate).readEntity(UserTO.class);
        assertNotNull(userTO);
        assertEquals("active", userTO.getStatus());

        assertEquals(0, goodPwdClient.self().getValue().getFailedLogins(), 0);
    }

    @Test
    public void issueSYNCOPE434() {
        Assume.assumeTrue(ActivitiDetector.isActivitiEnabledForUsers(syncopeService));

        // 1. create user with group 9 (users with group 9 are defined in workflow as subject to approval)
        UserTO userTO = UserITCase.getUniqueSampleTO("createWithReject@syncope.apache.org");
        MembershipTO membershipTO = new MembershipTO();
        membershipTO.setRightKey(9L);
        userTO.getMemberships().add(membershipTO);

        userTO = createUser(userTO);
        assertNotNull(userTO);
        assertEquals("createApproval", userTO.getStatus());

        // 2. try to authenticate: fail
        try {
            clientFactory.create(userTO.getUsername(), "password123").self();
            fail();
        } catch (AccessControlException e) {
            assertNotNull(e);
        }

        // 3. approve user
        WorkflowFormTO form = userWorkflowService.getFormForUser(userTO.getKey());
        form = userWorkflowService.claimForm(form.getTaskId());
        Map<String, WorkflowFormPropertyTO> props = form.getPropertyMap();
        props.get("approve").setValue(Boolean.TRUE.toString());
        form.getProperties().clear();
        form.getProperties().addAll(props.values());
        userTO = userWorkflowService.submitForm(form);
        assertNotNull(userTO);
        assertEquals("active", userTO.getStatus());

        // 4. try to authenticate again: success
        Pair<Map<String, Set<String>>, UserTO> self = clientFactory.create(userTO.getUsername(), "password123")
                .self();
        assertNotNull(self);
        assertNotNull(self.getKey());
        assertNotNull(self.getValue());
    }

    @Test
    public void issueSYNCOPE164() throws Exception {
        // 1. create user with db resource
        UserTO user = UserITCase.getUniqueSampleTO("syncope164@syncope.apache.org");
        user.setRealm("/even/two");
        user.setPassword("password123");
        user.getResources().add(RESOURCE_NAME_TESTDB);
        user = createUser(user);
        assertNotNull(user);

        // 2. unlink the resource from the created user
        assertNotNull(userService
                .bulkDeassociation(user.getKey(), ResourceDeassociationActionType.UNLINK,
                        CollectionWrapper.wrap(RESOURCE_NAME_TESTDB, ResourceKey.class))
                .readEntity(BulkActionResult.class));

        // 3. change password on Syncope
        UserMod userMod = new UserMod();
        userMod.setKey(user.getKey());
        userMod.setPassword("password234");
        user = updateUser(userMod);
        assertNotNull(user);

        // 4. check that the db resource has still the initial password value
        final JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
        String value = jdbcTemplate.queryForObject("SELECT PASSWORD FROM test WHERE ID=?", String.class,
                user.getUsername());
        assertEquals(Encryptor.getInstance().encode("password123", CipherAlgorithm.SHA1), value.toUpperCase());

        // 5. successfully authenticate with old (on db resource) and new (on internal storage) password values
        Pair<Map<String, Set<String>>, UserTO> self = clientFactory.create(user.getUsername(), "password123")
                .self();
        assertNotNull(self);
        self = clientFactory.create(user.getUsername(), "password234").self();
        assertNotNull(self);
    }
}