Search in sources :

Example 1 with RegistrarModule

use of cz.metacentrum.perun.registrar.RegistrarModule in project perun by CESNET.

the class RegistrarManagerImpl method getRegistrarModule.

/**
	 * Return RegistrarModule for specific application form (VO or Group)
	 * so it can be used for more actions.
	 *
	 * @param form
	 * @return RegistrarModule if present or null
	 */
private RegistrarModule getRegistrarModule(ApplicationForm form) {
    if (form == null) {
        // wrong input
        log.error("[REGISTRAR] Application form is null when getting it's registrar module.");
        throw new NullPointerException("Application form is null when getting it's registrar module.");
    }
    if (form.getModuleClassName() != null && !form.getModuleClassName().trim().isEmpty()) {
        RegistrarModule module = null;
        try {
            log.debug("[REGISTRAR] Attempting to instantiate class: {}", MODULE_PACKAGE_PATH + form.getModuleClassName());
            module = (RegistrarModule) Class.forName(MODULE_PACKAGE_PATH + form.getModuleClassName()).newInstance();
            module.setRegistrar(registrarManager);
        } catch (Exception ex) {
            log.error("[REGISTRAR] Exception when instantiating module: {}", ex);
            return module;
        }
        log.debug("[REGISTRAR] Class {} successfully created.", MODULE_PACKAGE_PATH + form.getModuleClassName());
        return module;
    }
    return null;
}
Also used : RegistrarModule(cz.metacentrum.perun.registrar.RegistrarModule) SQLException(java.sql.SQLException) EmptyResultDataAccessException(org.springframework.dao.EmptyResultDataAccessException) DuplicateKeyException(org.springframework.dao.DuplicateKeyException)

Example 2 with RegistrarModule

use of cz.metacentrum.perun.registrar.RegistrarModule in project perun by CESNET.

the class RegistrarManagerImpl method canBeApproved.

@Override
public void canBeApproved(PerunSession session, Application application) throws PerunException {
    // authz
    if (!AuthzResolver.isAuthorized(session, Role.VOADMIN, application.getVo())) {
        if (application.getGroup() != null) {
            if (!AuthzResolver.isAuthorized(session, Role.GROUPADMIN, application.getGroup())) {
                throw new PrivilegeException(session, "canBeApproved");
            }
        } else {
            throw new PrivilegeException(session, "canBeApproved");
        }
    }
    // get registrar module
    RegistrarModule module;
    if (application.getGroup() != null) {
        module = getRegistrarModule(getFormForGroup(application.getGroup()));
    } else {
        module = getRegistrarModule(getFormForVo(application.getVo()));
    }
    if (module != null) {
        // call custom logic before approving
        module.canBeApproved(session, application);
    }
    // meaning, user should submit membership extension application first !!
    if (application.getGroup() != null && application.getType().equals(AppType.INITIAL)) {
        try {
            User u = application.getUser();
            if (u == null) {
                u = usersManager.getUserByExtSourceNameAndExtLogin(registrarSession, application.getExtSourceName(), application.getCreatedBy());
            }
            Member member = membersManager.getMemberByUser(registrarSession, application.getVo(), u);
            if (!Arrays.asList(Status.VALID, Status.INVALID).contains(member.getStatus())) {
                throw new CantBeApprovedException("Application of member with membership status: " + member.getStatus() + " can't be approved. Please wait until member extends/re-validate own membership in a VO.");
            }
        } catch (MemberNotExistsException | UserNotExistsException | ExtSourceNotExistsException | UserExtSourceNotExistsException ex) {
            throw new RegistrarException("To approve application user must already be member of VO.", ex);
        }
    }
}
Also used : RegistrarModule(cz.metacentrum.perun.registrar.RegistrarModule)

Example 3 with RegistrarModule

use of cz.metacentrum.perun.registrar.RegistrarModule in project perun by CESNET.

the class RegistrarManagerImpl method getFormItemsWithPrefilledValues.

@Override
public List<ApplicationFormItemWithPrefilledValue> getFormItemsWithPrefilledValues(PerunSession sess, AppType appType, ApplicationForm form) throws PerunException {
    Vo vo = form.getVo();
    Group group = form.getGroup();
    // refresh session (user) to get correct data
    AuthzResolverBlImpl.refreshSession(sess);
    // get necessary params from session
    User user = sess.getPerunPrincipal().getUser();
    String actor = sess.getPerunPrincipal().getActor();
    String extSourceName = sess.getPerunPrincipal().getExtSourceName();
    String extSourceType = sess.getPerunPrincipal().getExtSourceType();
    int extSourceLoa = sess.getPerunPrincipal().getExtSourceLoa();
    Map<String, String> federValues = sess.getPerunPrincipal().getAdditionalInformations();
    RegistrarModule module = getRegistrarModule(form);
    if (module != null)
        module.canBeSubmitted(sess, federValues);
    // Check if it's not DuplicateRegistrationAttempt (for initial)
    if (AppType.INITIAL.equals(appType)) {
        List<Integer> regs = new ArrayList<Integer>();
        if (user != null) {
            // user is known
            try {
                Member m = membersManager.getMemberByUser(registrarSession, vo, user);
                if (group != null) {
                    // get members groups
                    List<Group> g = perun.getGroupsManager().getMemberGroups(registrarSession, m);
                    if (g.contains(group)) {
                        // user is member of group - can't post more initial applications
                        throw new AlreadyRegisteredException("You are already member of group " + group.getName() + ".");
                    } else {
                        // user isn't member of group
                        regs.clear();
                        regs.addAll(jdbc.query("select id from application where apptype=? and vo_id=? and group_id=? and state=? and (user_id=? or (created_by=? and extSourceName=?))", new SingleColumnRowMapper<Integer>(Integer.class), AppType.INITIAL.toString(), vo.getId(), group.getId(), AppState.NEW.toString(), user.getId(), actor, extSourceName));
                        regs.addAll(jdbc.query("select id from application where apptype=? and vo_id=? and group_id=? and state=? and (user_id=? or (created_by=? and extSourceName=?))", new SingleColumnRowMapper<Integer>(Integer.class), AppType.INITIAL.toString(), vo.getId(), group.getId(), AppState.VERIFIED.toString(), user.getId(), actor, extSourceName));
                        if (!regs.isEmpty()) {
                            // user have unprocessed application for group
                            throw new DuplicateRegistrationAttemptException("Initial application for Group: " + group.getName() + " already exists.", actor, extSourceName, regs.get(0));
                        }
                    // pass if have approved or rejected app
                    }
                } else {
                    // user is member of vo, can't post more initial applications
                    throw new AlreadyRegisteredException("You are already member of VO: " + vo.getName());
                }
            } catch (MemberNotExistsException ex) {
                // user is not member of vo
                if (group != null) {
                    // not member of VO - check for unprocessed applications to Group
                    regs.clear();
                    regs.addAll(jdbc.query("select id from application where apptype=? and vo_id=? and group_id=? and state=? and (user_id=? or (created_by=? and extSourceName=?))", new SingleColumnRowMapper<Integer>(Integer.class), AppType.INITIAL.toString(), vo.getId(), group.getId(), AppState.NEW.toString(), user.getId(), actor, extSourceName));
                    regs.addAll(jdbc.query("select id from application where apptype=? and vo_id=? and group_id=? and state=? and (user_id=? or (created_by=? and extSourceName=?))", new SingleColumnRowMapper<Integer>(Integer.class), AppType.INITIAL.toString(), vo.getId(), group.getId(), AppState.VERIFIED.toString(), user.getId(), actor, extSourceName));
                    if (!regs.isEmpty()) {
                        // user have unprocessed application for group - can't post more
                        throw new DuplicateRegistrationAttemptException("Initial application for Group: " + group.getName() + " already exists.", actor, extSourceName, regs.get(0));
                    }
                //throw new InternalErrorException("You must be member of vo: "+vo.getName()+" to apply for membership in group: "+group.getName());
                } else {
                    // not member of VO - check for unprocessed applications
                    regs.clear();
                    regs.addAll(jdbc.query("select id from application where apptype=? and vo_id=? and group_id is null and state=? and (user_id=? or (created_by=? and extSourceName=?))", new SingleColumnRowMapper<Integer>(Integer.class), AppType.INITIAL.toString(), vo.getId(), AppState.NEW.toString(), user.getId(), actor, extSourceName));
                    regs.addAll(jdbc.query("select id from application where apptype=? and vo_id=? and group_id is null and state=? and (user_id=? or (created_by=? and extSourceName=?))", new SingleColumnRowMapper<Integer>(Integer.class), AppType.INITIAL.toString(), vo.getId(), AppState.VERIFIED.toString(), user.getId(), actor, extSourceName));
                    if (!regs.isEmpty()) {
                        // user have unprocessed application for VO - can't post more
                        throw new DuplicateRegistrationAttemptException("Initial application for VO: " + vo.getName() + " already exists.", actor, extSourceName, regs.get(0));
                    }
                // pass not member and have only approved or rejected apps
                }
            }
        } else {
            // user is not known
            if (group != null) {
                // group application
                // get registrations by user logged identity
                regs.addAll(jdbc.query("select id from application where apptype=? and vo_id=? and group_id=? and created_by=? and extSourceName=? and state<>?", new SingleColumnRowMapper<Integer>(Integer.class), AppType.INITIAL.toString(), vo.getId(), group.getId(), actor, extSourceName, AppState.REJECTED.toString()));
                if (!regs.isEmpty()) {
                    throw new DuplicateRegistrationAttemptException("Initial application for Group: " + group.getName() + " already exists.", actor, extSourceName, regs.get(0));
                }
            } else {
                // vo application
                // get registrations by user logged identity
                regs.addAll(jdbc.query("select id from application where apptype=? and vo_id=? and group_id is null and created_by=? and extSourceName=? and state<>?", new SingleColumnRowMapper<Integer>(Integer.class), AppType.INITIAL.toString(), vo.getId(), actor, extSourceName, AppState.REJECTED.toString()));
                if (!regs.isEmpty()) {
                    throw new DuplicateRegistrationAttemptException("Initial application for VO: " + vo.getName() + " already exists", actor, extSourceName, regs.get(0));
                }
            }
        }
        // if false, throws exception with reason for GUI
        membersManager.canBeMemberWithReason(sess, vo, user, String.valueOf(extSourceLoa));
    }
    // if extension, user != null !!
    if (AppType.EXTENSION.equals(appType)) {
        if (user == null) {
            throw new RegistrarException("Trying to get extension application for non-existing user. Try to log-in with different identity known to Perun.");
        }
        if (form.getGroup() != null) {
            throw new RegistrarException("You are already member of group " + form.getGroup().getShortName() + ".");
        }
        // check for submitted registrations (only for VO)
        List<Integer> regs = new ArrayList<Integer>();
        regs.addAll(jdbc.query("select id from application where apptype=? and vo_id=? and group_id is null and user_id=? and state=?", new SingleColumnRowMapper<Integer>(Integer.class), AppType.EXTENSION.toString(), vo.getId(), user.getId(), AppState.NEW.toString()));
        regs.addAll(jdbc.query("select id from application where apptype=? and vo_id=? and group_id is null and user_id=? and state=?", new SingleColumnRowMapper<Integer>(Integer.class), AppType.EXTENSION.toString(), vo.getId(), user.getId(), AppState.VERIFIED.toString()));
        if (!regs.isEmpty()) {
            // user have unprocessed application for group
            throw new DuplicateRegistrationAttemptException("Extension application for VO: " + vo.getName() + " already exists.", actor, extSourceName, regs.get(0));
        }
        Member member = membersManager.getMemberByUser(sess, vo, user);
        // if false, throws exception with reason for GUI
        membersManager.canExtendMembershipWithReason(sess, member);
    }
    // PROCEED
    Map<String, String> parsedName = extractNames(federValues);
    List<ApplicationFormItem> formItems = getFormItems(registrarSession, form, appType);
    List<ApplicationFormItemWithPrefilledValue> itemsWithValues = new ArrayList<ApplicationFormItemWithPrefilledValue>();
    for (ApplicationFormItem item : formItems) {
        itemsWithValues.add(new ApplicationFormItemWithPrefilledValue(item, null));
    }
    // get user and member attributes from DB for existing users
    if (user != null) {
        Map<String, Attribute> map = new HashMap<String, Attribute>();
        // process user attributes
        List<Attribute> userAttributes = attrManager.getAttributes(registrarSession, user);
        for (Attribute att : userAttributes) {
            map.put(att.getName(), att);
        }
        // process member attributes
        try {
            Member member = membersManager.getMemberByUser(registrarSession, vo, user);
            List<Attribute> memberAttributes = attrManager.getAttributes(registrarSession, member);
            for (Attribute att : memberAttributes) {
                map.put(att.getName(), att);
            }
        } catch (MemberNotExistsException ex) {
        // we don't care that user is not yet member
        }
        Iterator<ApplicationFormItemWithPrefilledValue> it = ((Collection<ApplicationFormItemWithPrefilledValue>) itemsWithValues).iterator();
        while (it.hasNext()) {
            ApplicationFormItemWithPrefilledValue itemW = it.next();
            String dstAtt = itemW.getFormItem().getPerunDestinationAttribute();
            // skip items without perun attr reference
            if (dstAtt == null || dstAtt.equals(""))
                continue;
            // if attr exist and value != null
            if (map.get(dstAtt) != null && map.get(dstAtt).getValue() != null) {
                if (itemW.getFormItem().getType() == PASSWORD) {
                    // if login in namespace exists, do not return password field
                    // because application form is not place to change login or password
                    it.remove();
                } else {
                    // else set value
                    itemW.setPrefilledValue(BeansUtils.attributeValueToString(map.get(dstAtt)));
                }
            }
        }
    }
    List<ApplicationFormItemWithPrefilledValue> itemsWithMissingData = new ArrayList<ApplicationFormItemWithPrefilledValue>();
    // get user attributes from federation
    Iterator<ApplicationFormItemWithPrefilledValue> it = (itemsWithValues).iterator();
    while (it.hasNext()) {
        ApplicationFormItemWithPrefilledValue itemW = it.next();
        String fa = itemW.getFormItem().getFederationAttribute();
        if (fa != null && !fa.isEmpty()) {
            // FILL VALUE FROM FEDERATION
            String s = federValues.get(fa);
            if (s != null && !s.isEmpty()) {
                // In case of email, value from the federation can contain more than one entries, entries are separated by semi-colon
                if (itemW.getFormItem().getType().equals(ApplicationFormItem.Type.VALIDATED_EMAIL)) {
                    if (itemW.getPrefilledValue() != null && !itemW.getPrefilledValue().isEmpty()) {
                        s = itemW.getPrefilledValue() + ";" + s;
                    }
                }
                // remove password field if (login) prefilled from federation
                if (itemW.getFormItem().getType() == PASSWORD) {
                    it.remove();
                    continue;
                }
                itemW.setPrefilledValue(s);
                itemW.setAssuranceLevel(federValues.get(shibLoAVar));
            }
            // TRY TO CONSTRUCT THE VALUE FROM PARTIAL FED-INFO
            ApplicationFormItem item = itemW.getFormItem();
            String dstAtt = item.getPerunDestinationAttribute();
            if (URN_USER_TITLE_BEFORE.equals(dstAtt)) {
                String titleBefore = parsedName.get("titleBefore");
                if (titleBefore != null && !titleBefore.trim().isEmpty())
                    itemW.setPrefilledValue(titleBefore);
            } else if (URN_USER_TITLE_AFTER.equals(dstAtt)) {
                String titleAfter = parsedName.get("titleAfter");
                if (titleAfter != null && !titleAfter.trim().isEmpty())
                    itemW.setPrefilledValue(titleAfter);
            } else if (URN_USER_FIRST_NAME.equals(dstAtt)) {
                String firstName = parsedName.get("firstName");
                if (firstName != null && !firstName.trim().isEmpty())
                    itemW.setPrefilledValue(firstName);
            } else if (URN_USER_LAST_NAME.equals(dstAtt)) {
                String lastName = parsedName.get("lastName");
                if (lastName != null && !lastName.trim().isEmpty())
                    itemW.setPrefilledValue(lastName);
            } else if (URN_USER_DISPLAY_NAME.equals(dstAtt)) {
                // overwrite only if not filled by Perun
                if (itemW.getPrefilledValue() == null || itemW.getPrefilledValue().isEmpty()) {
                    String displayName = "";
                    if (parsedName.get("titleBefore") != null && !parsedName.get("titleBefore").isEmpty())
                        displayName += parsedName.get("titleBefore");
                    if (parsedName.get("firstName") != null && !parsedName.get("firstName").isEmpty()) {
                        if (!displayName.isEmpty())
                            displayName += " ";
                        displayName += parsedName.get("firstName");
                    }
                    if (parsedName.get("lastName") != null && !parsedName.get("lastName").isEmpty()) {
                        if (!displayName.isEmpty())
                            displayName += " ";
                        displayName += parsedName.get("lastName");
                    }
                    if (parsedName.get("titleAfter") != null && !parsedName.get("titleAfter").isEmpty()) {
                        if (!displayName.isEmpty())
                            displayName += " ";
                        displayName += parsedName.get("titleAfter");
                    }
                    itemW.setPrefilledValue(displayName);
                }
            }
            // We do require value from IDP (federation) if attribute is supposed to be pre-filled and item is required and not editable to users
            if ((itemW.getPrefilledValue() == null || itemW.getPrefilledValue().isEmpty()) && itemW.getFormItem().isRequired() && (Type.FROM_FEDERATION_HIDDEN.equals(itemW.getFormItem().getType()) || Type.FROM_FEDERATION_SHOW.equals(itemW.getFormItem().getType()))) {
                itemsWithMissingData.add(itemW);
            }
        }
    }
    if (!itemsWithMissingData.isEmpty() && extSourceType.equals(ExtSourcesManager.EXTSOURCE_IDP)) {
        // throw exception only if user is logged-in by Federation IDP
        String IDP = federValues.get("Shib-Identity-Provider");
        log.error("[REGISTRAR] IDP {} doesn't provide data for following form items: {}", IDP, itemsWithMissingData);
        throw new MissingRequiredDataException("Your IDP doesn't provide data required by this application form.", itemsWithMissingData);
    }
    // return prefilled form
    return itemsWithValues;
}
Also used : SingleColumnRowMapper(org.springframework.jdbc.core.SingleColumnRowMapper) ApplicationFormItemWithPrefilledValue(cz.metacentrum.perun.registrar.model.ApplicationFormItemWithPrefilledValue) ApplicationFormItem(cz.metacentrum.perun.registrar.model.ApplicationFormItem) RegistrarModule(cz.metacentrum.perun.registrar.RegistrarModule)

Example 4 with RegistrarModule

use of cz.metacentrum.perun.registrar.RegistrarModule in project perun by CESNET.

the class RegistrarManagerImpl method approveApplicationInternal.

/**
	 * Process application approval in 1 transaction
	 * !! WITHOUT members validation !!
	 *
	 * @param sess session for authz
	 * @param appId application ID to approve
	 * @return updated application
	 * @throws PerunException
	 */
@Transactional(rollbackFor = Exception.class)
public Application approveApplicationInternal(PerunSession sess, int appId) throws PerunException {
    Application app = getApplicationById(appId);
    Member member = null;
    // authz
    if (!AuthzResolver.isAuthorized(sess, Role.VOADMIN, app.getVo())) {
        if (app.getGroup() != null) {
            if (!AuthzResolver.isAuthorized(sess, Role.GROUPADMIN, app.getGroup())) {
                throw new PrivilegeException(sess, "approveApplication");
            }
        } else {
            throw new PrivilegeException(sess, "approveApplication");
        }
    }
    // only VERIFIED applications can be approved
    if (!AppState.VERIFIED.equals(app.getState())) {
        if (AppState.APPROVED.equals(app.getState()))
            throw new RegistrarException("Application is already approved. Try to refresh the view to see changes.");
        if (AppState.REJECTED.equals(app.getState()))
            throw new RegistrarException("Rejected application cant' be approved. Try to refresh the view to see changes.");
        throw new RegistrarException("User didn't verify his email address yet. Please wait until application will be in a 'Submitted' state. You can send mail verification notification to user again if you wish.");
    }
    // get registrar module
    RegistrarModule module;
    if (app.getGroup() != null) {
        module = getRegistrarModule(getFormForGroup(app.getGroup()));
    } else {
        module = getRegistrarModule(getFormForVo(app.getVo()));
    }
    if (module != null) {
        // call custom logic before approving
        module.beforeApprove(sess, app);
    }
    // mark as APPROVED
    int result = jdbc.update("update application set state=?, modified_by=?, modified_at=? where id=?", AppState.APPROVED.toString(), sess.getPerunPrincipal().getActor(), new Date(), appId);
    if (result == 0) {
        throw new RegistrarException("Application with ID=" + appId + " not found.");
    } else if (result > 1) {
        throw new ConsistencyErrorException("More than one application is stored under ID=" + appId + ".");
    }
    // set back as approved
    app.setState(AppState.APPROVED);
    log.info("Application {} marked as APPROVED", appId);
    // Try to get reservedLogin and reservedNamespace before deletion, it will be used for creating userExtSources
    List<Pair<String, String>> logins;
    try {
        logins = jdbc.query("select namespace,login from application_reserved_logins where app_id=?", new RowMapper<Pair<String, String>>() {

            @Override
            public Pair<String, String> mapRow(ResultSet rs, int arg1) throws SQLException {
                return new Pair<String, String>(rs.getString("namespace"), rs.getString("login"));
            }
        }, appId);
    } catch (EmptyResultDataAccessException e) {
        // set empty logins
        logins = new ArrayList<Pair<String, String>>();
    }
    // FOR INITIAL APPLICATION
    if (AppType.INITIAL.equals(app.getType())) {
        if (app.getGroup() != null) {
            // free reserved logins so they can be set as attributes
            jdbc.update("delete from application_reserved_logins where app_id=?", appId);
            if (app.getUser() == null) {
                // application for group doesn't have user set, but it can exists in perun (joined identities after submission)
                User u = usersManager.getUserByExtSourceNameAndExtLogin(registrarSession, app.getExtSourceName(), app.getCreatedBy());
                // put user back to application
                app.setUser(u);
                // store user_id in DB
                int result2 = jdbc.update("update application set user_id=? where id=?", u.getId(), appId);
                if (result2 == 0) {
                    throw new RegistrarException("Application with ID=" + appId + " not found.");
                } else if (result2 > 1) {
                    throw new ConsistencyErrorException("More than one application is stored under ID=" + appId + ".");
                }
            }
            // add new member of VO as member of group (for group applications)
            // !! MUST BE MEMBER OF VO !!
            member = membersManager.getMemberByUser(registrarSession, app.getVo(), app.getUser());
            // meaning, user should submit membership extension application first !!
            if (!Arrays.asList(Status.VALID, Status.INVALID).contains(member.getStatus())) {
                throw new CantBeApprovedException("Application of member with membership status: " + member.getStatus() + " can't be approved. Please wait until member extends/re-validate own membership in a VO.");
            }
            // store all attributes (but not logins)
            storeApplicationAttributes(app);
            // cancel reservation of new duplicate logins and get purely new logins back
            logins = unreserveNewLoginsFromSameNamespace(logins, app.getUser());
            // store purely new logins to user
            storeApplicationLoginAttributes(app);
            for (Pair<String, String> pair : logins) {
                // LOGIN IN NAMESPACE IS PURELY NEW => VALIDATE ENTRY IN KDC
                // left = namespace, right = login
                perun.getUsersManagerBl().validatePasswordAndSetExtSources(registrarSession, app.getUser(), pair.getRight(), pair.getLeft());
            }
            // update titles before/after users name if part of application !! USER MUST EXISTS !!
            updateUserNameTitles(app);
            perun.getGroupsManager().addMember(registrarSession, app.getGroup(), member);
            log.debug("[REGISTRAR] Member {} added to Group {}.", member, app.getGroup());
        } else {
            // put application data into Candidate
            final Map<String, String> attributes = new HashMap<String, String>();
            jdbc.query("select dst_attr,value from application_data d, application_form_items i where d.item_id=i.id " + "and i.dst_attr is not null and d.value is not null and app_id=?", new RowMapper<Object>() {

                @Override
                public Object mapRow(ResultSet rs, int i) throws SQLException {
                    attributes.put(rs.getString("dst_attr"), rs.getString("value"));
                    return null;
                }
            }, appId);
            // DO NOT STORE LOGINS THROUGH CANDIDATE
            // we do not set logins by candidate object to prevent accidental overwrite while joining identities in process
            Iterator<Map.Entry<String, String>> iter = attributes.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, String> entry = iter.next();
                if (entry.getKey().contains("urn:perun:user:attribute-def:def:login-namespace:")) {
                    iter.remove();
                }
            }
            Candidate candidate = new Candidate();
            candidate.setAttributes(attributes);
            log.debug("[REGISTRAR] Retrieved candidate from DB {}", candidate);
            // first try to parse display_name if not null and not empty
            if (attributes.containsKey(URN_USER_DISPLAY_NAME) && attributes.get(URN_USER_DISPLAY_NAME) != null && !attributes.get(URN_USER_DISPLAY_NAME).isEmpty()) {
                // parse
                Map<String, String> commonName = Utils.parseCommonName(attributes.get(URN_USER_DISPLAY_NAME));
                if (commonName.get("titleBefore") != null && !commonName.get("titleBefore").isEmpty()) {
                    candidate.setTitleBefore(commonName.get("titleBefore"));
                }
                if (commonName.get("firstName") != null && !commonName.get("firstName").isEmpty()) {
                    candidate.setFirstName(commonName.get("firstName"));
                }
                // FIXME - ? there is no middleName in Utils.parseCommonName() implementation
                if (commonName.get("middleName") != null && !commonName.get("middleName").isEmpty()) {
                    candidate.setMiddleName(commonName.get("middleName"));
                }
                if (commonName.get("lastName") != null && !commonName.get("lastName").isEmpty()) {
                    candidate.setLastName(commonName.get("lastName"));
                }
                if (commonName.get("titleAfter") != null && !commonName.get("titleAfter").isEmpty()) {
                    candidate.setTitleAfter(commonName.get("titleAfter"));
                }
            }
            // if names are separated, used them after
            for (String attrName : attributes.keySet()) {
                // if value not null or empty - set to candidate
                if (attributes.get(attrName) != null && !attributes.get(attrName).isEmpty()) {
                    if (URN_USER_TITLE_BEFORE.equals(attrName)) {
                        candidate.setTitleBefore(attributes.get(attrName));
                    } else if (URN_USER_TITLE_AFTER.equals(attrName)) {
                        candidate.setTitleAfter(attributes.get(attrName));
                    } else if (URN_USER_FIRST_NAME.equals(attrName)) {
                        candidate.setFirstName(attributes.get(attrName));
                    } else if (URN_USER_LAST_NAME.equals(attrName)) {
                        candidate.setLastName(attributes.get(attrName));
                    } else if (URN_USER_MIDDLE_NAME.equals(attrName)) {
                        candidate.setMiddleName(attributes.get(attrName));
                    }
                }
            }
            // free reserved logins so they can be set as attributes
            jdbc.update("delete from application_reserved_logins where app_id=?", appId);
            // create member and user
            log.debug("[REGISTRAR] Trying to make member from candidate {}", candidate);
            member = membersManager.createMember(sess, app.getVo(), app.getExtSourceName(), app.getExtSourceType(), app.getExtSourceLoa(), app.getCreatedBy(), candidate);
            User u = usersManager.getUserById(registrarSession, member.getUserId());
            if (app.getUser() != null) {
                // if user was already known to perun, createMember() will set attributes
                // via setAttributes() method so core attributes are skipped
                // ==> updateNameTitles() in case of change in appForm.
                updateUserNameTitles(app);
            }
            // set NEW user id back to application
            app.setUser(u);
            result = jdbc.update("update application set user_id=? where id=?", member.getUserId(), appId);
            if (result == 0) {
                throw new RegistrarException("User ID hasn't been associated with the application " + appId + ", because the application was not found!");
            } else if (result > 1) {
                throw new ConsistencyErrorException("User ID hasn't been associated with the application " + appId + ", because more than one application exists under the same ID.");
            }
            log.info("Member " + member.getId() + " created for: " + app.getCreatedBy() + " / " + app.getExtSourceName());
            // unreserve new login if user already have login in same namespace
            // also get back purely new logins
            logins = unreserveNewLoginsFromSameNamespace(logins, u);
            // store purely new logins to user
            storeApplicationLoginAttributes(app);
            for (Pair<String, String> pair : logins) {
                // LOGIN IN NAMESPACE IS PURELY NEW => VALIDATE ENTRY IN KDC
                // left = namespace, right = login
                perun.getUsersManagerBl().validatePasswordAndSetExtSources(registrarSession, u, pair.getRight(), pair.getLeft());
            }
            // log
            perun.getAuditer().log(sess, "{} created for approved {}.", member, app);
        }
    // FOR EXTENSION APPLICATION
    } else if (AppType.EXTENSION.equals(app.getType())) {
        // free reserved logins so they can be set as attributes
        jdbc.update("delete from application_reserved_logins where app_id=?", app.getId());
        member = membersManager.getMemberByUser(registrarSession, app.getVo(), app.getUser());
        storeApplicationAttributes(app);
        // extend user's membership
        membersManager.extendMembership(registrarSession, member);
        // unreserve new logins, if user already have login in same namespace
        // also get back logins, which are purely new
        logins = unreserveNewLoginsFromSameNamespace(logins, app.getUser());
        // store purely new logins from application
        storeApplicationLoginAttributes(app);
        // validate purely new logins in KDC
        for (Pair<String, String> pair : logins) {
            // left = namespace, right = login
            perun.getUsersManagerBl().validatePasswordAndSetExtSources(registrarSession, app.getUser(), pair.getRight(), pair.getLeft());
        }
        // update titles before/after users name if part of application !! USER MUST EXISTS !!
        updateUserNameTitles(app);
        // log
        perun.getAuditer().log(sess, "Membership extended for {} in {} for approved {}.", member, app.getVo(), app);
    }
    if (module != null) {
        module.approveApplication(sess, app);
    }
    getMailManager().sendMessage(app, MailType.APP_APPROVED_USER, null, null);
    // return updated application
    return app;
}
Also used : SQLException(java.sql.SQLException) ResultSet(java.sql.ResultSet) SingleColumnRowMapper(org.springframework.jdbc.core.SingleColumnRowMapper) RowMapper(org.springframework.jdbc.core.RowMapper) EmptyResultDataAccessException(org.springframework.dao.EmptyResultDataAccessException) RegistrarModule(cz.metacentrum.perun.registrar.RegistrarModule) Application(cz.metacentrum.perun.registrar.model.Application) Transactional(org.springframework.transaction.annotation.Transactional)

Example 5 with RegistrarModule

use of cz.metacentrum.perun.registrar.RegistrarModule in project perun by CESNET.

the class RegistrarManagerImpl method createApplicationInternal.

@Override
@Transactional(rollbackFor = ApplicationNotCreatedException.class)
public Application createApplicationInternal(PerunSession session, Application application, List<ApplicationFormItemData> data) throws PerunException {
    // exceptions to send to vo admin with new app created email
    List<Exception> exceptions = new ArrayList<Exception>();
    boolean applicationNotCreated = false;
    try {
        // 1) create application
        int appId = Utils.getNewId(jdbc, "APPLICATION_ID_SEQ");
        application.setId(appId);
        application.setState(AppState.NEW);
        // optional group
        Integer groupId = null;
        Integer userId = null;
        if (application.getGroup() != null) {
            groupId = application.getGroup().getId();
        }
        if (application.getUser() != null) {
            userId = application.getUser().getId();
        }
        jdbc.update("insert into application(id,vo_id,group_id,user_id,apptype,fed_info,extSourceName,extSourceType,extSourceLoa,state,created_by,modified_by) values (?,?,?,?,?,?,?,?,?,?,?,?)", appId, application.getVo().getId(), groupId, userId, application.getType().toString(), application.getFedInfo(), application.getExtSourceName(), application.getExtSourceType(), application.getExtSourceLoa(), application.getState().toString(), application.getCreatedBy(), application.getCreatedBy());
        // 2) process & store app data
        for (ApplicationFormItemData itemData : data) {
            Type itemType = itemData.getFormItem().getType();
            if (itemType == HTML_COMMENT || itemType == SUBMIT_BUTTON || itemType == AUTO_SUBMIT_BUTTON || itemType == PASSWORD || itemType == HEADING)
                continue;
            // Check if mails needs to be validated
            if (itemType == VALIDATED_EMAIL) {
                // default = mail not same as pre-filled
                itemData.setAssuranceLevel("");
                // We must use contains, because IdP can send more than one email, emails are separated by semi-colon
                if (itemData.getPrefilledValue() != null && itemData.getValue() != null && !itemData.getValue().isEmpty()) {
                    if (itemData.getPrefilledValue().toLowerCase().contains(itemData.getValue().toLowerCase())) {
                        itemData.setAssuranceLevel("1");
                    }
                }
                // it's save, empty attributes are not set to DB nor any notification is sent
                if (!itemData.getFormItem().isRequired() && (itemData.getValue() == null || itemData.getValue().isEmpty())) {
                    itemData.setAssuranceLevel("1");
                }
            }
            try {
                itemData.setId(Utils.getNewId(jdbc, "APPLICATION_DATA_ID_SEQ"));
                jdbc.update("insert into application_data(id,app_id,item_id,shortname,value,assurance_level) values (?,?,?,?,?,?)", itemData.getId(), appId, itemData.getFormItem().getId(), itemData.getFormItem().getShortname(), itemData.getValue(), itemData.getAssuranceLevel());
            } catch (Exception ex) {
                // log and store exception so vo manager could see error in notification.
                log.error("[REGISTRAR] Storing form item {} caused exception {}", itemData, ex);
                exceptions.add(ex);
            }
        }
        // 3) process all logins and passwords
        // create list of logins and passwords to process
        List<ApplicationFormItemData> logins = new ArrayList<ApplicationFormItemData>();
        for (ApplicationFormItemData itemData : data) {
            Type itemType = itemData.getFormItem().getType();
            if (itemType == USERNAME || itemType == PASSWORD) {
                // skip unchanged pre-filled logins, since they must have been handled last time
                if (itemData.getValue().equals(itemData.getPrefilledValue()) && itemType != PASSWORD)
                    continue;
                logins.add(itemData);
            }
        }
        for (ApplicationFormItemData loginItem : logins) {
            if (loginItem.getFormItem().getType() == USERNAME) {
                // values to store
                String login = loginItem.getValue();
                // filled later
                String pass = "";
                // Get login namespace
                String dstAttr = loginItem.getFormItem().getPerunDestinationAttribute();
                AttributeDefinition loginAttribute = attrManager.getAttributeDefinition(registrarSession, dstAttr);
                String loginNamespace = loginAttribute.getFriendlyNameParameter();
                // try to book new login in namespace if the application hasn't been approved yet
                if (perun.getUsersManagerBl().isLoginAvailable(registrarSession, loginNamespace, login)) {
                    try {
                        // Reserve login
                        jdbc.update("insert into application_reserved_logins(login,namespace,app_id,created_by,created_at) values(?,?,?,?,?)", login, loginNamespace, appId, application.getCreatedBy(), new Date());
                        log.debug("[REGISTRAR] Added login reservation for login: {} in namespace: {}.", login, loginNamespace);
                        // process password for this login
                        for (ApplicationFormItemData passItem : logins) {
                            ApplicationFormItem item = passItem.getFormItem();
                            if (item.getType() == PASSWORD && item.getPerunDestinationAttribute() != null) {
                                if (item.getPerunDestinationAttribute().equals(dstAttr)) {
                                    pass = passItem.getValue();
                                    try {
                                        // reserve password
                                        perun.getUsersManagerBl().reservePassword(registrarSession, login, loginNamespace, pass);
                                        log.debug("[REGISTRAR] Password for login: {} in namespace: {} successfully reserved in external system.", login, loginNamespace);
                                    } catch (Exception ex) {
                                        // login reservation fail must cause rollback !!
                                        log.error("[REGISTRAR] Unable to reserve password for login: {} in namespace: {} in external system. Exception: " + ex, login, loginNamespace);
                                        throw new ApplicationNotCreatedException("Application was not created. Reason: Unable to reserve password for login: " + login + " in namespace: " + loginNamespace + " in external system. Please contact support to fix this issue before new application submission.", login, loginNamespace);
                                    }
                                    // use first pass with correct namespace
                                    break;
                                }
                            }
                        }
                    } catch (ApplicationNotCreatedException ex) {
                        // re-throw
                        throw ex;
                    } catch (Exception ex) {
                        // unable to book login
                        log.error("[REGISTRAR] Unable to reserve login: {} in namespace: {}. Exception: " + ex, login, loginNamespace);
                        exceptions.add(ex);
                    }
                } else {
                    // login is not available
                    log.error("[REGISTRAR] Login: " + login + " in namespace: " + loginNamespace + " is already occupied but it shouldn't (race condition).");
                    exceptions.add(new InternalErrorException("Login: " + login + " in namespace: " + loginNamespace + " is already occupied but it shouldn't."));
                }
            }
        }
        // call registrar module before auto validation so createAction is trigerred first
        RegistrarModule module;
        if (application.getGroup() != null) {
            module = getRegistrarModule(getFormForGroup(application.getGroup()));
        } else {
            module = getRegistrarModule(getFormForVo(application.getVo()));
        }
        if (module != null) {
            module.createApplication(session, application, data);
        }
    } catch (ApplicationNotCreatedException ex) {
        // prevent action in finally block
        applicationNotCreated = true;
        // re-throw
        throw ex;
    } catch (Exception ex) {
        // any exception during app creation process => add it to list
        // exceptions when handling logins are catched before
        log.error("{}", ex);
        exceptions.add(ex);
    } finally {
        // process rest only if it was not exception related to PASSWORDS creation
        if (!applicationNotCreated) {
            getMailManager().sendMessage(application, MailType.APP_CREATED_USER, null, null);
            getMailManager().sendMessage(application, MailType.APP_CREATED_VO_ADMIN, null, exceptions);
            // if there were exceptions, throw some to let know GUI about it
            if (!exceptions.isEmpty()) {
                RegistrarException ex = new RegistrarException("Your application (ID=" + application.getId() + ") has been created with errors. Administrator of " + application.getVo().getName() + " has been notified. If you want, you can use \"Send report to RT\" button to send this information to administrators directly.");
                log.error("[REGISTRAR] New application {} created with errors {}. This is case of PerunException {}", new Object[] { application, exceptions, ex.getErrorId() });
                throw ex;
            }
            log.info("New application {} created.", application);
            perun.getAuditer().log(session, "New {} created.", application);
        }
    }
    // return stored data
    return application;
}
Also used : ApplicationFormItemData(cz.metacentrum.perun.registrar.model.ApplicationFormItemData) SQLException(java.sql.SQLException) EmptyResultDataAccessException(org.springframework.dao.EmptyResultDataAccessException) DuplicateKeyException(org.springframework.dao.DuplicateKeyException) ApplicationFormItem(cz.metacentrum.perun.registrar.model.ApplicationFormItem) MailType(cz.metacentrum.perun.registrar.model.ApplicationMail.MailType) Type(cz.metacentrum.perun.registrar.model.ApplicationFormItem.Type) AppType(cz.metacentrum.perun.registrar.model.Application.AppType) RegistrarModule(cz.metacentrum.perun.registrar.RegistrarModule) Transactional(org.springframework.transaction.annotation.Transactional)

Aggregations

RegistrarModule (cz.metacentrum.perun.registrar.RegistrarModule)6 SQLException (java.sql.SQLException)4 EmptyResultDataAccessException (org.springframework.dao.EmptyResultDataAccessException)3 Transactional (org.springframework.transaction.annotation.Transactional)3 Application (cz.metacentrum.perun.registrar.model.Application)2 ApplicationFormItem (cz.metacentrum.perun.registrar.model.ApplicationFormItem)2 ResultSet (java.sql.ResultSet)2 DuplicateKeyException (org.springframework.dao.DuplicateKeyException)2 SingleColumnRowMapper (org.springframework.jdbc.core.SingleColumnRowMapper)2 AppType (cz.metacentrum.perun.registrar.model.Application.AppType)1 Type (cz.metacentrum.perun.registrar.model.ApplicationFormItem.Type)1 ApplicationFormItemData (cz.metacentrum.perun.registrar.model.ApplicationFormItemData)1 ApplicationFormItemWithPrefilledValue (cz.metacentrum.perun.registrar.model.ApplicationFormItemWithPrefilledValue)1 MailType (cz.metacentrum.perun.registrar.model.ApplicationMail.MailType)1 RowMapper (org.springframework.jdbc.core.RowMapper)1