de.hska.ld.oidc.listeners.LDToSSSEventListener.java Source code

Java tutorial

Introduction

Here is the source code for de.hska.ld.oidc.listeners.LDToSSSEventListener.java

Source

/*
 *  Code contributed to the Learning Layers project
 *  http://www.learning-layers.eu
 *  Development is partly funded by the FP7 Programme of the European
 *  Commission under Grant Agreement FP7-ICT-318209.
 *  Copyright (c) 2015, Karlsruhe University of Applied Sciences.
 *  For a list of contributors see the AUTHORS file at the top-level directory
 *  of this distribution.
 *
 *  Licensed 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 de.hska.ld.oidc.listeners;

import de.hska.ld.content.dto.DocumentListItemDto;
import de.hska.ld.content.events.document.*;
import de.hska.ld.content.persistence.domain.Access;
import de.hska.ld.content.persistence.domain.Document;
import de.hska.ld.content.service.DocumentService;
import de.hska.ld.core.events.user.UserFirstLoginEvent;
import de.hska.ld.core.events.user.UserLoginEvent;
import de.hska.ld.core.exception.UserNotAuthorizedException;
import de.hska.ld.core.logging.ExceptionLogger;
import de.hska.ld.core.persistence.domain.ExceptionLogEntry;
import de.hska.ld.core.persistence.domain.User;
import de.hska.ld.core.service.UserService;
import de.hska.ld.oidc.client.SSSClient;
import de.hska.ld.oidc.client.exception.AuthenticationNotValidException;
import de.hska.ld.oidc.client.exception.CreationFailedException;
import de.hska.ld.oidc.dto.*;
import de.hska.ld.oidc.persistence.domain.DocumentSSSInfo;
import de.hska.ld.oidc.persistence.domain.UserSSSInfo;
import de.hska.ld.oidc.persistence.domain.UserSharingBuffer;
import de.hska.ld.oidc.service.DocumentSSSInfoService;
import de.hska.ld.oidc.service.UserSSSInfoService;
import de.hska.ld.oidc.service.UserSharingBufferService;
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.exceptions.UnauthorizedClientException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

@Transactional
@Component("ld-oidc-LDToSSSEventListener")
public class LDToSSSEventListener {

    @Autowired
    private SSSClient sssClient;

    @Autowired
    private DocumentService documentService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserSSSInfoService userSSSInfoService;

    @Autowired
    private ExceptionLogger exceptionLogger;

    @Autowired
    private UserSharingBufferService userSharingBufferService;

    @Autowired
    private DocumentSSSInfoService documentSSSInfoService;

    @Async
    @EventListener
    public void handleDocumentReadEvent(DocumentReadEvent event) throws IOException, CreationFailedException {
        Document document = (Document) event.getSource();
        System.out.println(
                "LDToSSSEventListener: Reading document=" + document.getId() + ", title=" + document.getTitle());
        document = createAndShareLDocWithSSSUsers(document, "READ", event.getAccessToken(), null);
        event.setResultDocument(document);
    }

    @Async
    @EventListener
    public void handleDocumentCreationEvent(DocumentCreationEvent event)
            throws IOException, CreationFailedException {
        Document newDocument = (Document) event.getSource();
        System.out.println("LDToSSSEventListener: Creating document=" + newDocument.getId() + ", title="
                + newDocument.getTitle());
        newDocument = createAndShareLDocWithSSSUsers(newDocument, "WRITE", event.getAccessToken(), null);
        SSSCreateDiscRequestDto sssCreateDiscRequestDto = new SSSCreateDiscRequestDto();
        sssCreateDiscRequestDto.setLabel(newDocument.getTitle());
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        OIDCAuthenticationToken token = (OIDCAuthenticationToken) auth;
        createDefaultDiscussion(event, newDocument, sssCreateDiscRequestDto);
        event.setResultDocument(newDocument);
    }

    @EventListener
    public void handleDocumentDeletionEvent(DocumentDeletionEvent event)
            throws IOException, CreationFailedException {
        Long documentId = (long) event.getSource();
        System.out.println("LDToSSSEventListener: Deleting document=" + documentId);
        preventDeletionOfConnectedDocuments(event, documentId);
    }

    @EventListener
    public void handleDocumentReadListEvent(DocumentReadListEvent event) {
        checkIfDocumentsHaveAnAttachedEpisode(event);
    }

    private void checkIfDocumentsHaveAnAttachedEpisode(DocumentReadListEvent event) {
        Page<Document> documentPage = (Page<Document>) event.getSource();
        List<DocumentListItemDto> documentListItemDtoList = new ArrayList<>();

        documentPage.forEach(doc -> {
            Long documentId = doc.getId();
            DocumentSSSInfo documentSSSInfo = documentSSSInfoService.getDocumentSSSInfoById(documentId);
            DocumentListItemDto documentListItemDto = new DocumentListItemDto(doc);
            if (documentSSSInfo != null) {
                documentListItemDto.setHasConnectedEpisode(true);
            }
            documentListItemDtoList.add(documentListItemDto);
        });

        try {
            Field pageableField = PageImpl.class.getSuperclass().getDeclaredField("pageable");
            pageableField.setAccessible(true);
            Pageable pageable = (Pageable) pageableField.get(documentPage);
            Page<DocumentListItemDto> documentListItemDtoPage = new PageImpl<DocumentListItemDto>(
                    documentListItemDtoList, pageable, documentPage.getTotalElements());
            event.setResultDocument(documentListItemDtoPage);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private void preventDeletionOfConnectedDocuments(DocumentDeletionEvent event, Long documentId) {
        Document document = documentService.findById(documentId);
        if (document == null) {
            event.setDeletable(true);
        } else {
            DocumentSSSInfo documentSSSInfo = documentSSSInfoService.getDocumentSSSInfo(document);
            if (documentSSSInfo == null || documentSSSInfo.getEpisodeId() == null) {
                event.setDeletable(true);
            }
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private void createDefaultDiscussion(DocumentCreationEvent event, Document newDocument,
            SSSCreateDiscRequestDto sssCreateDiscRequestDto) {
        try {
            String episodeId = null;
            try {
                Document document = documentService.findById(newDocument.getId());
                if (document != null) {
                    DocumentSSSInfo documentSSSInfo = documentSSSInfoService.getDocumentSSSInfo(document);
                    if (documentSSSInfo != null) {
                        episodeId = documentSSSInfo.getEpisodeId();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            SSSCreateDiscResponseDto result = sssClient.createDiscussion(String.valueOf(newDocument.getId()),
                    sssCreateDiscRequestDto, event.getAccessToken(), episodeId);
            String disc = result.getDisc();
            System.out.println(disc);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Async
    @EventListener
    public void handleDocumentSharingEvent(DocumentSharingEvent event) throws IOException, CreationFailedException {
        Document document = (Document) event.getSource();
        System.out.println(
                "LDToSSSEventListener: Sharing document=" + document.getId() + ", title=" + document.getTitle());
        document = createAndShareLDocWithSSSUsers(document, "READ", event.getAccessToken(), event.getAccessList());
        event.setResultDocument(document);
    }

    @Async
    @EventListener
    public void handleLoginEvent(UserLoginEvent event) throws IOException {
        User user = (User) event.getSource();
        checkIfSSSUserInfoIsKnown(user, event.getAccessToken());
    }

    @Async
    @EventListener
    public void handleFirstLoginEvent(UserFirstLoginEvent event) throws IOException {
        User user = (User) event.getSource();
        sharePreviouslySharedDocumentsWithTheNewUser(user, event);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private void sharePreviouslySharedDocumentsWithTheNewUser(User user, UserFirstLoginEvent event) {
        UserSharingBuffer userSharingBuffer = userSharingBufferService.findByEmail(user.getEmail());
        if (userSharingBuffer == null) {
            userSharingBuffer = userSharingBufferService.findBySubAndIssuer(user.getSubId(), user.getIssuer());
        }
        if (userSharingBuffer != null) {
            String userIds = user.getId().toString();
            if (!"".equals(userIds)) {
                Document dbDocument = documentService.findById(userSharingBuffer.getDocumentId());
                documentService.addAccessWithoutTransactional(dbDocument.getId(), userIds,
                        userSharingBuffer.getPermissionString());
                try {
                    System.out.println("LDToSSSEventListener: Sharing document=" + dbDocument.getId() + ", title="
                            + dbDocument.getTitle());
                    createAndShareLDocWithSSSUsers(dbDocument, "READ", event.getAccessToken(), null);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                userSharingBufferService.removeUserSharingBuffer(userSharingBuffer.getId());
            }
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private void checkIfSSSUserInfoIsKnown(User user, String accessTokenValue) throws IOException {
        user = userService.findById(user.getId());
        UserSSSInfo userSSSInfo = userSSSInfoService.findByUser(user);
        // if the sss user id is already known to the server do nothing
        if (userSSSInfo == null) {
            // else authenticate towards the sss to retrieve the sss user id
            // and save that user id in the ldocs database
            SSSAuthDto sssAuthDto = null;
            try {
                sssAuthDto = sssClient.authenticate(accessTokenValue);
                String sssUserId = sssAuthDto.getUser();
                userSSSInfoService.addUserSSSInfo(user.getId(), sssUserId);
            } catch (UserNotAuthorizedException e) {
                e.printStackTrace();
                throw new UnauthorizedClientException("oidc token invalid");
            }
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private Document createAndShareLDocWithSSSUsers(Document document, String cmd, String accessToken,
            List<Access> accessList) throws IOException, CreationFailedException {
        // Create the document as well in the SSS
        document = documentService.findById(document.getId());
        if (accessList == null) {
            accessList = document.getAccessList();
        }
        List<String> emailAddressesThatHaveAccess = new ArrayList<>();
        for (Access access : accessList) {
            emailAddressesThatHaveAccess.add(access.getUser().getEmail());
        }
        // check if the living document is already known to the SSS
        //Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        //OIDCAuthenticationToken token = (OIDCAuthenticationToken) auth;
        boolean isAlreadyKnownToSSS = false;
        String sssLivingDocId = null;
        Long newDocumentId = document.getId();
        try {
            SSSLivingDocResponseDto documentFoundInSSS = sssClient.getLDocById(newDocumentId, accessToken);
            if (documentFoundInSSS != null) {
                SSSLivingdoc documentFoundInSSSLDoc = documentFoundInSSS.getLivingDoc();
                if (documentFoundInSSSLDoc != null && documentFoundInSSSLDoc.getId() != null) {
                    isAlreadyKnownToSSS = true;
                } else if ("READ".equals(cmd)) {
                    exceptionLogger.log("createAndShareLDocWithSSSUsers (READ)",
                            "Could not find the document in the SSS!", ExceptionLogEntry.LogLevel.FATAL);
                }
            } else if ("READ".equals(cmd)) {
                exceptionLogger.log("createAndShareLDocWithSSSUsers (READ)",
                        "Could not find the document in the SSS!", ExceptionLogEntry.LogLevel.FATAL);
            }
            if (!isAlreadyKnownToSSS) {
                // create the living document in the SSS
                SSSLivingdocsResponseDto sssLivingdocsResponseDto2 = null;
                sssLivingdocsResponseDto2 = sssClient.createDocument(document, null, accessToken);
                sssLivingDocId = sssLivingdocsResponseDto2.getLivingDoc();
                if (sssLivingDocId == null) {
                    throw new CreationFailedException(newDocumentId);
                }
            }
            // Retrieve users/emails that have access to this living document declared by the SSS
            SSSLivingDocResponseDto sssLivingdocsResponseDto = sssClient.getLDocEmailsById(newDocumentId,
                    accessToken);
            SSSLivingdoc sssLivingDoc = sssLivingdocsResponseDto.getLivingDoc();
            if (sssLivingDoc != null && sssLivingDoc.getUsers() != null) {
                StringBuilder sb = new StringBuilder();
                boolean first = true;
                // TODO share living documents in the sss with all users that are
                // present within living documents but not within the sss
                // after the sharing the other way round happened
                List<String> checkedEmailAddresses = new ArrayList<>();
                for (SSSUserDto userDto : sssLivingDoc.getUsers()) {
                    boolean found = emailAddressesThatHaveAccess.contains(userDto.getLabel());
                    checkedEmailAddresses.add(userDto.getLabel());
                    if (!found) {
                        User user = userService.findByEmail(userDto.getLabel());
                        if (user != null && user.getId() != null && document.getCreator() != null
                                && document.getCreator().getId() != null
                                && !user.getId().equals(document.getCreator().getId())) {
                            if (first) {
                                sb.append(user.getId());
                                first = false;
                            } else {
                                sb.append(";").append(user.getId());
                            }
                        }
                    }
                }
                String userIds = sb.toString();
                try {
                    if (!"".equals(userIds)) {
                        Document dbDocument = documentService.findById(document.getId());
                        dbDocument = documentService.addAccessWithoutTransactional(dbDocument.getId(), userIds,
                                "READ;WRITE");
                        dbDocument.getAttachmentList().size();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                emailAddressesThatHaveAccess.removeAll(checkedEmailAddresses);
                if (emailAddressesThatHaveAccess.size() > 0) {
                    List<String> sssUserIdsTheLDocIsNotSharedWith = new ArrayList<>();
                    emailAddressesThatHaveAccess.forEach(email -> {
                        UserSSSInfo sssUserInfo = userSSSInfoService.findByUserEmail(email);
                        if (sssUserInfo != null) {
                            sssUserIdsTheLDocIsNotSharedWith.add(sssUserInfo.getSssUserId());
                        } else {
                            System.out.println("No sss user id found for email address=" + email);
                        }
                    });
                    sssClient.shareLDocWith(document.getId(), sssUserIdsTheLDocIsNotSharedWith, accessToken);
                }
            }
        } catch (AuthenticationNotValidException eAuth) {
            eAuth.printStackTrace();
        }
        return document;
    }
}