001/*
002 * This file is part of the Keycloak Moodle authenticator
003 * Copyright (C) 2024 Michael N. Lipp
004 *
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Lesser General Public License as published
007 * by the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
013 * License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License along 
016 * with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jdrupes.keycloak.moodleauth.moodle;
020
021import java.io.IOException;
022import java.net.URI;
023import java.net.URISyntaxException;
024import java.util.Collections;
025import java.util.Map;
026import java.util.logging.Logger;
027import org.jdrupes.keycloak.moodleauth.moodle.actions.MoodleGetSiteInfo;
028import org.jdrupes.keycloak.moodleauth.moodle.actions.MoodleUserByName;
029import org.jdrupes.keycloak.moodleauth.moodle.model.MoodleSiteInfo;
030import org.jdrupes.keycloak.moodleauth.moodle.model.MoodleTokens;
031import org.jdrupes.keycloak.moodleauth.moodle.model.MoodleUser;
032import org.jdrupes.keycloak.moodleauth.moodle.service.MoodleAuthFailedException;
033import org.jdrupes.keycloak.moodleauth.moodle.service.MoodleClient;
034import org.jdrupes.keycloak.moodleauth.moodle.service.MoodleService;
035import org.jdrupes.keycloak.moodleauth.moodle.service.Password;
036
037/**
038 * Represents an open connection to a moodle instance.
039 */
040public class MoodleServiceProvider implements MoodleService {
041
042    @SuppressWarnings({ "PMD.FieldNamingConventions",
043        "PMD.UnusedPrivateField", "unused" })
044    private static final Logger logger
045        = Logger.getLogger(MoodleServiceProvider.class.getName());
046
047    @Override
048    @SuppressWarnings({ "PMD.AvoidCatchingGenericException",
049        "PMD.EmptyCatchBlock" })
050    public MoodleClient connect(String website, String username,
051            Password password) throws IOException, MoodleAuthFailedException {
052        // Request token
053        try {
054            String site = website;
055            if (!site.contains("://")) {
056                site = "https://" + site;
057            }
058            URI siteUri = new URI("https", "localhost", null, null, null)
059                .resolve(site);
060            if ("".equals(siteUri.getPath())) {
061                siteUri = siteUri.resolve(new URI(null, null, "/", null, null));
062            }
063            URI tokenUri = siteUri
064                .resolve(new URI(null, null, "login/token.php", null, null));
065            var restClient = new RestClient(tokenUri);
066            var tokens = restClient.invoke(MoodleTokens.class,
067                Map.of("username", username,
068                    "password", new String(password.password()),
069                    "service", "moodle_mobile_app"),
070                Collections.emptyMap());
071            if (tokens.getErrorcode() != null) {
072                try {
073                    restClient.close();
074                } catch (Exception e) {
075                    // Was just trying to be nice
076                }
077                throw new MoodleAuthFailedException(tokens.getError());
078            }
079            URI serviceUri = siteUri.resolve(
080                new URI(null, null, "webservice/rest/server.php", null, null));
081            restClient.setUri(serviceUri);
082            restClient.setDefaultParams(Map.of("wstoken", tokens.getToken(),
083                "moodlewsrestformat", "json"));
084            MoodleUser muser
085                = new MoodleUserByName(restClient).invoke(username);
086            MoodleSiteInfo siteInfo
087                = new MoodleGetSiteInfo(restClient).invoke();
088            return new MoodleClientConnection(siteUri, restClient, muser,
089                siteInfo);
090        } catch (URISyntaxException e) {
091            throw new IllegalArgumentException(e);
092        }
093    }
094}