org.apigw.authserver.web.controller.ApplicationManagementController.java Source code

Java tutorial

Introduction

Here is the source code for org.apigw.authserver.web.controller.ApplicationManagementController.java

Source

/**
 *   Copyright 2013 Stockholm County Council
 *
 *   This file is part of APIGW
 *
 *   APIGW is free software; you can redistribute it and/or modify
 *   it under the terms of version 2.1 of the GNU Lesser General Public
 *   License as published by the Free Software Foundation.
 *
 *   APIGW is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public
 *   License along with APIGW; if not, write to the
 *   Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 *   Boston, MA 02111-1307  USA
 *
 */
package org.apigw.authserver.web.controller;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apigw.appmanagement.ApplicationManagementService;
import org.apigw.appmanagement.domain.Application;
import org.apigw.appmanagement.domain.Application.State;
import org.apigw.appmanagement.domain.Certificate;
import org.apigw.appmanagement.domain.Developer;
import org.apigw.authserver.svc.PermissionServices;
import org.apigw.authserver.types.domain.Permission;
import org.apigw.authserver.types.domain.User;
import org.apigw.authserver.web.validator.ApplicationValidator;
import org.apigw.authserver.web.validator.DeveloperValidator;
import org.apigw.commons.logging.CitizenLoggingUtil;
import org.bouncycastle.openssl.PEMReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.ByteArrayMultipartFileEditor;
import org.springframework.web.servlet.ModelAndView;

@Controller
@SessionAttributes
@Transactional
@RequestMapping(value = "developer")
public class ApplicationManagementController {

    private static final Logger log = LoggerFactory.getLogger(ApplicationManagementController.class);

    @Autowired
    private ApplicationManagementService appManagement;

    @Autowired
    private PermissionServices permissionServices;

    @Autowired
    private DeveloperValidator developerValidator;

    @Autowired
    private ApplicationValidator applicationValidator;

    @Autowired
    private JavaMailSender sender;

    @Autowired
    private CitizenLoggingUtil citizenLoggingUtil;

    @Value("${applicationmanagement.notification.mail.to}")
    private String mailAddress;

    @Value("${applicationmanagement.notification.mail.from}")
    private String mailFrom;

    @Value("${monitoring.api.location}")
    private String location;// = "http://localhost:9000";

    private RestTemplate template = new RestTemplate();

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor());
    }

    @RequestMapping("")
    public ModelAndView listApps(Authentication authentication) {

        UserDetails user = (UserDetails) authentication.getPrincipal();
        log.debug("Logged in user is: {}", user.getUsername());

        if (!developerExists(user)) {
            return new ModelAndView("redirect:/developer/register_developer");
        } else { // ...otherwise, list the developers applications
            TreeMap<String, Object> model = new TreeMap<String, Object>();
            List<Application> apps = appManagement.getApplications(user.getUsername());

            Map<String, Integer> success = new HashMap<String, Integer>();
            Map<String, Integer> client_failure = new HashMap<String, Integer>();
            Map<String, Integer> server_failure = new HashMap<String, Integer>();

            for (Application app : apps) {

                // load statistics if client is in production
                if (app.getState() == State.IN_PRODUCTION) {
                    String id = app.getClientId();
                    success.put(id, getStats(id, "SUCCESS"));
                    client_failure.put(id, getStats(id, "CLIENT_FAILURE"));
                    server_failure.put(id, getStats(id, "SERVER_FAILURE"));
                }
            }

            model.put("apps", appManagement.getApplications(user.getUsername()));

            // TODO: cache this...
            Map<String, String> scopes = new HashMap<String, String>();
            for (Permission permission : permissionServices.getAllPermissions()) {
                scopes.put(permission.getName(), permission.getDescription());
            }

            model.put("scopes", scopes);
            model.put("success", success);
            model.put("client_failure", client_failure);
            model.put("server_failure", server_failure);
            return new ModelAndView("applications", model);
        }

    }

    @SuppressWarnings("unchecked")
    private int getStats(String id, String state) {
        List<Map<String, Object>> stats = template.getForObject(location
                + "/api/timeline/resourceRequestCount?categories=crm-scheduling," + id + "," + state + "&count=1",
                List.class);

        if (stats != null && stats.size() > 0) {
            return (Integer) stats.get(0).get("value");
        } else {
            return 0;
        }

    }

    @RequestMapping("register_developer")
    public ModelAndView registerDeveloper(ModelMap model, Authentication authentication) {
        // send the developer to the register account page if not already registred 
        UserDetails user = (UserDetails) authentication.getPrincipal();
        String fullname = (user instanceof User) ? ((User) user).getFullName() : "";

        Developer developer = new Developer();
        developer.setResidentIdentificationNumber(user.getUsername());
        developer.setName(fullname);
        model.addAttribute(developer);
        model.addAttribute("registered", false);
        return new ModelAndView("register_developer");
    }

    @RequestMapping("edit_developer")
    public ModelAndView editDeveloper(ModelMap model, Authentication authentication) {
        UserDetails user = (UserDetails) authentication.getPrincipal();

        Developer developer = appManagement.getDeveloper(user.getUsername());
        if (developer != null) {
            model.addAttribute(developer);
            model.addAttribute("registered", true);
            return new ModelAndView("register_developer");
        } else {
            return registerDeveloper(model, authentication);
        }
    }

    @RequestMapping(value = "register_developer", method = RequestMethod.POST)
    public String registerDeveloper(@ModelAttribute("developer") Developer developer, BindingResult result,
            Authentication authentication) {

        developerValidator.validate(developer, result);

        if (result.hasErrors()) {
            return "register_developer";
        } else {
            UserDetails user = (UserDetails) authentication.getPrincipal();

            log.debug("Logged in user is: {}", citizenLoggingUtil.getLogsafeSSN(user.getUsername()));

            if (developer.getResidentIdentificationNumber() == null) {
                developer.setResidentIdentificationNumber(user.getUsername());
            } else if (!developer.getResidentIdentificationNumber().equals(user.getUsername())) {
                throw new RuntimeException(
                        "The provided resident identification number isn't the same as the number for the logged in user");
            }

            String fullname = (user instanceof User) ? ((User) user).getFullName() : "";
            if (!fullname.equals(developer.getName())) {
                developer.setName(fullname);
            }

            appManagement.registerDeveloper(developer);
            return "redirect:";
        }
    }

    @RequestMapping(value = "/app", method = RequestMethod.GET, params = { "edit" })
    public ModelAndView editApp(@RequestParam("edit") Long id, ModelMap model, Authentication authentication) {
        Application application = appManagement.getApplication(id);
        UserDetails user = (UserDetails) authentication.getPrincipal();

        if (application == null) {
            throw new IllegalArgumentException("No application found with id " + id);
        }

        if (user.getUsername().equals(application.getDeveloper().getResidentIdentificationNumber())) {
            List<Permission> permissions = permissionServices.getAllPermissions();
            model.addAttribute("editIcon", false);
            model.addAttribute(application);
            model.addAttribute("scopes", permissions);
            return new ModelAndView("application/edit");
        } else {
            throw new IllegalArgumentException("Application developer is not the same as the logged in user");
        }
    }

    @RequestMapping(value = "/edit", method = RequestMethod.POST)
    public ModelAndView editApp(ModelMap model, Authentication authentication,
            @ModelAttribute("application") Application application, MultipartFile icon,
            @RequestParam(value = "certificate", required = false) MultipartFile certificate,
            BindingResult result) {
        UserDetails user = (UserDetails) authentication.getPrincipal();
        Developer developer = appManagement.getDeveloper(user.getUsername());
        List<Permission> permissions = permissionServices.getAllPermissions();

        log.debug("User {} registered or edited the app {}.", citizenLoggingUtil.getLogsafeSSN(user.getUsername()),
                application.getName());

        if (developer == null) {
            return new ModelAndView("redirect:register_developer");
        } else {

            applicationValidator.validate(application, result);

            log.info("app id: " + application.getId());
            Application dbApp = appManagement.getApplication(application.getId());

            if (!user.getUsername().equals(dbApp.getDeveloper().getResidentIdentificationNumber())) {
                throw new IllegalArgumentException(
                        "The application developer is not the same as the logged in user");
            }

            if (application.getIcon() == null && dbApp.getIcon() != null && dbApp.getIcon().length > 0) {
                application.setIcon(dbApp.getIcon());
                log.debug("Icon wasn't updated this time around");
            } else if (application.getIcon() != null) {
                log.debug("Icon was updated");
                try {
                    ByteArrayInputStream bis = new ByteArrayInputStream(application.getIcon());
                    BufferedImage bufferedImage = ImageIO.read(bis);
                    log.info("Width: " + bufferedImage.getWidth() + " Height: " + bufferedImage.getHeight());
                    application.setIconContentType(icon.getContentType());
                    // TODO: Check width and height here!
                } catch (Exception e) {
                    result.rejectValue("icon", "invalid.icon", "Ikonen r ej giltig");
                }
            }

            application.setCertificates(dbApp.getCertificates());
            application.setRegistrationDate(dbApp.getRegistrationDate());
            application.setState(dbApp.getState());
            application.setDeveloper(developer);

            //For now we are just allowing the addition of just one certificate
            List<Certificate> certs = new ArrayList<>();

            if (certificate != null && certificate.getSize() > 0) {
                certs.add(createCertificate(certificate, result));
            }

            //Error handling
            if (result.hasErrors()) {
                model.addAttribute(application);
                model.addAttribute("scopes", permissions);
                return new ModelAndView("application/edit");
            }

            Application savedApp = appManagement.updateApplication(application);

            //Remove everything old.
            // Just allow one certificate to be set right now even though the model allows for more.
            //If this behavior is unwanted the GUI has to adapt for this as well as it only caters
            //for on certificate right now.
            if (certificate != null && certificate.getSize() > 0) {
                Set<Certificate> oldCerts = new HashSet<>();

                //Clone in order to not get a concurrent modification exception
                for (Certificate cert : savedApp.getCertificates()) {
                    oldCerts.add(cert);
                }

                //Remove anything old
                for (Certificate cert : oldCerts) {
                    cert.setApplication(null);
                    savedApp.getCertificates().remove(cert);
                    appManagement.removeCertificate(cert);
                }

                //Set the new Certificate
                for (Certificate cert : certs) {
                    cert.setApplication(savedApp);
                    appManagement.saveCertificate(cert);
                    savedApp.getCertificates().add(cert);
                }
            }

            try {
                log.debug("Composing message to: {}", mailAddress);
                MimeMessage message = sender.createMimeMessage();
                MimeMessageHelper helper = new MimeMessageHelper(message);

                helper.setTo(mailAddress);
                helper.setFrom(new InternetAddress(mailFrom));

                log.debug("Creating message for existing app. User {} edited the app {}",
                        citizenLoggingUtil.getLogsafeSSN(user.getUsername()), application.getName());
                helper.setSubject("Redigerad app: " + application.getName());
                helper.setText("Utvecklare med personnr " + user.getUsername() + " har redigerat appen: "
                        + application.getName());

                log.debug("Sending mail notification.");
                sender.send(message);
            } catch (Exception e) {
                log.error("Caught exception while trying to send email", e);
            }
        }
        return new ModelAndView("redirect:/developer");
    }

    @RequestMapping(value = "/edit", method = RequestMethod.POST, params = { "edit_icon" })
    public ModelAndView editIcon(ModelMap model, Authentication authentication,
            @ModelAttribute("application") Application application) {
        UserDetails user = (UserDetails) authentication.getPrincipal();
        Developer developer = appManagement.getDeveloper(user.getUsername());

        Application savedApp = appManagement.getApplication(application.getId());
        //Repopulate the certificates. Maybe there is a better way..
        application.setCertificates(savedApp.getCertificates());

        if (application == null) {
            throw new IllegalArgumentException("No application found with");
        }

        if (user.getUsername().equals(developer.getResidentIdentificationNumber())) {
            List<Permission> permissions = permissionServices.getAllPermissions();
            model.addAttribute("editIcon", true);
            model.addAttribute(application);
            model.addAttribute("scopes", permissions);
            return new ModelAndView("application/edit");
        } else {
            throw new IllegalArgumentException("Application developer is not the same as the logged in user");
        }
    }

    @RequestMapping(value = "/edit", method = RequestMethod.POST, params = { "undo_edit_icon" })
    public ModelAndView undoEditIcon(ModelMap model, Authentication authentication,
            @ModelAttribute("application") Application application) {
        UserDetails user = (UserDetails) authentication.getPrincipal();
        Developer developer = appManagement.getDeveloper(user.getUsername());

        Application savedApp = appManagement.getApplication(application.getId());
        //Repopulate the certificates. Maybe there is a better way..
        application.setCertificates(savedApp.getCertificates());

        if (application == null) {
            throw new IllegalArgumentException("No application found with");
        }

        if (user.getUsername().equals(developer.getResidentIdentificationNumber())) {
            List<Permission> permissions = permissionServices.getAllPermissions();
            model.addAttribute("editIcon", false);
            model.addAttribute(application);
            model.addAttribute("scopes", permissions);
            return new ModelAndView("application/edit");
        } else {
            throw new IllegalArgumentException("Application developer is not the same as the logged in user");
        }
    }

    @RequestMapping(value = "/edit", method = RequestMethod.POST, params = { "edit_certificate" })
    public ModelAndView editCertificate(ModelMap model, Authentication authentication,
            @ModelAttribute("application") Application application) {
        UserDetails user = (UserDetails) authentication.getPrincipal();
        Developer developer = appManagement.getDeveloper(user.getUsername());

        if (application == null) {
            throw new IllegalArgumentException("No application found with");
        }

        if (user.getUsername().equals(developer.getResidentIdentificationNumber())) {
            List<Permission> permissions = permissionServices.getAllPermissions();
            model.addAttribute("editCertificate", true);
            model.addAttribute(application);
            model.addAttribute("scopes", permissions);
            return new ModelAndView("application/edit");
        } else {
            throw new IllegalArgumentException("Application developer is not the same as the logged in user");
        }
    }

    @RequestMapping(value = "/edit", method = RequestMethod.POST, params = { "undo_edit_certificate" })
    public ModelAndView undoEditCertificate(ModelMap model, Authentication authentication,
            @ModelAttribute("application") Application application) {
        UserDetails user = (UserDetails) authentication.getPrincipal();
        Developer developer = appManagement.getDeveloper(user.getUsername());

        Application savedApp = appManagement.getApplication(application.getId());
        //Repopulate the certificates. Maybe there is a better way..
        application.setCertificates(savedApp.getCertificates());

        if (application == null) {
            throw new IllegalArgumentException("No application found with");
        }

        if (user.getUsername().equals(developer.getResidentIdentificationNumber())) {
            List<Permission> permissions = permissionServices.getAllPermissions();
            model.addAttribute("editCertificate", false);
            model.addAttribute(application);
            model.addAttribute("scopes", permissions);
            return new ModelAndView("application/edit");
        } else {
            throw new IllegalArgumentException("Application developer is not the same as the logged in user");
        }
    }

    @RequestMapping(value = "/app", method = RequestMethod.GET, params = { "show" })
    public ModelAndView showApp(@RequestParam("show") Long id, ModelMap model, Authentication authentication) {
        log.debug("Entering Show");
        Application application = appManagement.getApplication(id);
        UserDetails user = (UserDetails) authentication.getPrincipal();

        if (!developerExists(user)) {
            return new ModelAndView("redirect:register_developer");
        }

        if (application == null) {
            throw new IllegalArgumentException("No application found with id " + id);
        }

        if (user.getUsername().equals(application.getDeveloper().getResidentIdentificationNumber())) {
            List<Permission> permissions = permissionServices.getAllPermissions();
            model.addAttribute(application);
            model.addAttribute("scopes", permissions);
            return new ModelAndView("application/show");
        } else {
            throw new IllegalArgumentException("Application developer is not the same as the logged in user");
        }
    }

    @RequestMapping(value = "/app", method = RequestMethod.GET)
    public ModelAndView registerApp(ModelMap model, Authentication authentication) {

        UserDetails user = (UserDetails) authentication.getPrincipal();

        if (!developerExists(user)) {
            return new ModelAndView("redirect:register_developer");
        } else {
            return renderAppForm(model, new Application());
        }
    }

    protected ModelAndView renderAppForm(ModelMap model, Application app) {
        List<Permission> permissions = permissionServices.getAllPermissions(); //new ArrayList(); //
        model.addAttribute(app);
        model.addAttribute("scopes", permissions);
        return new ModelAndView("register_application");
    }

    @RequestMapping(value = "/app", method = RequestMethod.POST)
    public String registerApp(ModelMap model, @ModelAttribute("application") Application application,
            @RequestParam("certificate") MultipartFile certificate, MultipartFile icon, BindingResult result,
            Authentication authentication) throws IOException {
        UserDetails user = (UserDetails) authentication.getPrincipal();
        Developer developer = appManagement.getDeveloper(user.getUsername());

        log.debug("User {} registered or edited the app {}.", citizenLoggingUtil.getLogsafeSSN(user.getUsername()),
                application.getName());

        if (developer == null) {
            return "redirect:register_developer";
        } else {

            applicationValidator.validate(application, result);

            application.setRegistrationDate(new Date());
            application.setState(State.REGISTRATED);

            application.setDeveloper(developer);

            Application existingApp = appManagement.getApplicationByClientId(application.getClientId());

            if (existingApp != null) {
                result.rejectValue("clientId", "invalid.clientId",
                        "Klient id:et finns redan registrerat, var god vlj ett annat.");
            }

            // validate icon if it exists
            if (application.getIcon() != null && application.getIcon().length > 0) {
                try {
                    ByteArrayInputStream bis = new ByteArrayInputStream(application.getIcon());
                    BufferedImage bufferedImage = ImageIO.read(bis);
                    log.info("Width: " + bufferedImage.getWidth() + " Height: " + bufferedImage.getHeight());
                    application.setIconContentType(icon.getContentType());
                    // TODO: Check width and height here!
                } catch (Exception e) {
                    result.rejectValue("icon", "invalid.icon", "Ikonen r ej giltig");
                }
            }

            //For now we are just allowing the addition of just one certificate
            List<Certificate> certs = new ArrayList<>();

            if (certificate != null && certificate.getSize() > 0) {
                certs.add(createCertificate(certificate, result));
            }

            if (result.hasErrors()) {
                List<Permission> permissions = permissionServices.getAllPermissions();
                model.addAttribute("scopes", permissions);
                return "register_application";
            }

            Application savedApp = appManagement.registerApplication(application);

            for (Certificate cert : certs) {
                cert.setApplication(savedApp);
                appManagement.saveCertificate(cert);
                savedApp.getCertificates().add(cert);
            }

            try {
                log.debug("Composing message to: {}", mailAddress);
                MimeMessage message = sender.createMimeMessage();
                MimeMessageHelper helper = new MimeMessageHelper(message);

                helper.setTo(mailAddress);
                helper.setFrom(new InternetAddress(mailFrom));

                log.debug("Creating message for existing app. User {} edited the app {}",
                        citizenLoggingUtil.getLogsafeSSN(user.getUsername()), application.getName());
                helper.setSubject("Redigerad app: " + application.getName());
                helper.setText("Utvecklare med personnr " + user.getUsername() + " har redigerat appen: "
                        + application.getName());

                log.debug("Sending mail notification.");
                sender.send(message);
            } catch (Exception e) {
                log.error("Caught exception while trying to send email", e);
            }

            return "redirect:";
        }
    }

    private Certificate createCertificate(MultipartFile certificate, BindingResult result) {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

        Certificate cert = new Certificate();
        if (certificate != null && certificate.getSize() > 0) {

            try {
                PEMReader r = new PEMReader(
                        new InputStreamReader(new ByteArrayInputStream(certificate.getBytes())));
                Object certObj = r.readObject();

                long reference = System.currentTimeMillis();

                // validate certificate
                if (certObj instanceof X509Certificate) {
                    X509Certificate x509cert = (X509Certificate) certObj;
                    BigInteger serialNumber = x509cert.getSerialNumber();

                    String issuerDn = x509cert.getIssuerDN().getName();
                    String subjectDn = x509cert.getSubjectDN().getName();

                    cert.setCertificate(certificate.getBytes());
                    cert.setSerialNumber(serialNumber.toString());
                    cert.setIssuer(issuerDn);
                    cert.setSubject(subjectDn);
                    cert.setSubjectCommonName(extractFromDn(subjectDn, "CN"));
                    cert.setSubjectOrganization(extractFromDn(subjectDn, "O"));
                    cert.setSubjectOrganizationUnit(extractFromDn(subjectDn, "OU"));
                    cert.setSubjectLocation(extractFromDn(subjectDn, "L"));
                    cert.setSubjectCountry(extractFromDn(subjectDn, "C"));
                    cert.setNotAfter(x509cert.getNotAfter());
                    cert.setNotBefore(x509cert.getNotBefore());
                } else {
                    String line;
                    StringBuilder certString = new StringBuilder();
                    while ((line = r.readLine()) != null) {
                        certString.append(line + "\n");
                    }
                    log.warn(
                            "Bad certificate [{}]: Provided certificate was of the wrong type: {}. Certificate: \n{}",
                            new Object[] { reference, certObj, certString.toString() });
                    result.rejectValue("certificates", "invalid.certificate",
                            "Certifikatet r ej giltigt (Reference: " + reference + ")");
                }

                r.close();
            } catch (IOException e) {
                log.warn("Bad certificate");
                result.rejectValue("certificates", "invalid.certificate", "Certifikatet r ej giltigt ");
            }
        }
        return cert;
    }

    protected String extractFromDn(String dn, String unit) {
        Pattern subjectDnPattern = Pattern.compile(unit + "=([^,]*)", Pattern.CASE_INSENSITIVE);
        Matcher matcher = subjectDnPattern.matcher(dn);

        if (matcher.find()) {
            return matcher.group(1);
        } else {
            return null;
        }
    }

    @RequestMapping(value = "/app", params = { "delete" })
    public ModelAndView deleteApp(@RequestParam("delete") Long id, Authentication authentication) {
        UserDetails user = (UserDetails) authentication.getPrincipal();
        Developer developer = appManagement.getDeveloper(user.getUsername());

        log.debug("User {} deleted the app with id {}.", citizenLoggingUtil.getLogsafeSSN(user.getUsername()), id);

        if (developer == null) {
            return new ModelAndView("redirect:register_developer");
        } else {
            Application application = appManagement.getApplication(id);
            log.debug("Deleting the app {}.", application.getName());

            if (application.getDeveloper().getResidentIdentificationNumber().equals(user.getUsername())) {
                appManagement.removeApplication(id);

                try {
                    MimeMessage message = sender.createMimeMessage();
                    MimeMessageHelper helper = new MimeMessageHelper(message);

                    helper.setTo(mailAddress);
                    helper.setFrom(new InternetAddress(mailFrom));
                    helper.setSubject("Borttagen app: " + application.getName());
                    helper.setText("Utvecklare med personnr " + user.getUsername() + " har tagit bort appen: "
                            + application.getName());
                    sender.send(message);
                } catch (Exception e) {
                    log.error("Caught exception while trying to send email", e);
                }

            } else {
                throw new RuntimeException(
                        "The logged in user is not the same as the developer of the application!");
            }

            return new ModelAndView("redirect:");
        }
    }

    private boolean developerExists(UserDetails user) {
        Developer developer = appManagement.getDeveloper(user.getUsername());
        return developer != null;
    }

    @RequestMapping(value = "/app/image", method = RequestMethod.GET, params = { "id" })
    public ResponseEntity<byte[]> getIcon(@RequestParam("id") Long id) {
        Application application = appManagement.getApplication(id);

        if (application == null) {
            throw new IllegalArgumentException("No application found with id " + id);
        }
        byte[] content = application.getIcon();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_JPEG);
        return new ResponseEntity<byte[]>(content, headers, HttpStatus.OK);
    }
}