diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/data-context.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/data-context.xml deleted file mode 100644 index 67d8bd146..000000000 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/data-context.xml +++ /dev/null @@ -1,128 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - Copyright 2018 The MIT Internet Trust Consortium - - Portions copyright 2011-2013 The MITRE Corporation - - 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. - --> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:jdbc="http://www.springframework.org/schema/jdbc" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd - http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd"> - - <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"> - <property name="driverClassName" value="org.hsqldb.jdbcDriver" /> - <property name="jdbcUrl" value="jdbc:hsqldb:mem:oic;sql.syntax_mys=true" /> -<!-- <property name="jdbcUrl" value="jdbc:hsqldb:file:/tmp/oic;sql.syntax_mys=true" /> --> - <property name="username" value="oic" /> - <property name="password" value="oic" /> - </bean> - - <!-- Use the following to set up the OIC tables in the in-memory DB - If you are using a file based HSQLDB you should not run this every time. --> - <jdbc:initialize-database data-source="dataSource"> - <jdbc:script location="classpath:/db/hsql/hsql_database_tables.sql"/> - <!-- The following file is for the jdbc-user-service spring security implementation --> - <jdbc:script location="classpath:/db/hsql/security-schema.sql"/> - <!-- The following files are for safely bootstrapping users and clients into the database --> - <jdbc:script location="classpath:/db/hsql/loading_temp_tables.sql"/> - <jdbc:script location="classpath:/db/hsql/users.sql"/> - <jdbc:script location="classpath:/db/hsql/clients.sql"/> - <jdbc:script location="classpath:/db/hsql/scopes.sql"/> - </jdbc:initialize-database> - - <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> - <property name="databasePlatform" value="org.eclipse.persistence.platform.database.HSQLPlatform" /> - <property name="showSql" value="true" /> - </bean> - - <!-- The following is for connecting to a MySQL database that has been initialized with - src/main/resources/db/mysql/mysql_database_tables.sql --> -<!-- <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"> --> -<!-- <property name="driverClassName" value="com.mysql.jdbc.Driver" /> --> -<!-- <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/oic" /> --> -<!-- <property name="username" value="oic" /> --> -<!-- <property name="password" value="oic" /> --> -<!-- </bean> --> - -<!-- <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> --> -<!-- <property name="databasePlatform" value="org.eclipse.persistence.platform.database.MySQLPlatform" /> --> -<!-- <property name="showSql" value="true" /> --> -<!-- </bean> --> - - <!-- You can optionally initialize the database with test values here, - but this is not recommended for real systems --> -<!-- <jdbc:initialize-database data-source="dataSource"> --> -<!-- <jdbc:script location="classpath:/db/tables/mysql_database_tables.sql"/> --> -<!-- <jdbc:script location="classpath:/db/tables/security-schema.sql"/> --> -<!-- <jdbc:script location="classpath:/db/tables/loading_temp_tables.sql"/> --> -<!-- <jdbc:script location="classpath:/db/mysql/users.sql"/> --> -<!-- <jdbc:script location="classpath:/db/mysql/clients.sql"/> --> -<!-- <jdbc:script location="classpath:/db/mysql/scopes.sql"/> --> -<!-- </jdbc:initialize-database> --> - - <!-- The following is for connecting to a PostgreSQL database that has been initialized with - src/main/resources/db/psql/psql_database_tables.sql --> - <!-- - <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"> - <property name="driverClassName" value="org.postgresql.Driver" /> - <property name="jdbcUrl" value="jdbc:postgresql://localhost/oic" /> - <property name="username" value="oic" /> - <property name="password" value="oic" /> - </bean> - - - <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> - <property name="databasePlatform" value="org.eclipse.persistence.platform.database.PostgreSQLPlatform" /> - <property name="showSql" value="true" /> - </bean> - --> - - <!-- You can optionally initialize the database with test values here, - but this is not recommended for real systems --> -<!-- <jdbc:initialize-database data-source="dataSource"> --> -<!-- <jdbc:script location="classpath:/db/psql/psql_database_tables.sql"/> --> -<!-- <jdbc:script location="classpath:/db/psql/security-schema.sql"/> --> -<!-- <jdbc:script location="classpath:/db/psql/loading_temp_tables.sql"/> --> -<!-- <jdbc:script location="classpath:/db/psql/users.sql"/> --> -<!-- <jdbc:script location="classpath:/db/psql/clients.sql"/> --> -<!-- <jdbc:script location="classpath:/db/psql/scopes.sql"/> --> -<!-- </jdbc:initialize-database> --> - - <!-- The following is for connecting to a Oracle database that has been initialized with - src/main/resources/db/oracle/oracle_database_tables.sql --> - <!--<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"> - <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> - <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:XE" /> - <property name="username" value="oic" /> - <property name="password" value="oic" /> - </bean>--> - - <!--<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> - <property name="databasePlatform" value="org.eclipse.persistence.platform.database.OraclePlatform" /> - <property name="showSql" value="true" /> - </bean>--> - - <!-- Use the following to set up the OIC tables in the Oracle DB - Below scripts are intended to be run once at startup. --> - <!--<jdbc:initialize-database data-source="dataSource"> - <jdbc:script location="classpath:/db/oracle/oracle_database_tables.sql"/> - <jdbc:script location="classpath:/db/oracle/security-schema_oracle.sql"/> - <jdbc:script location="classpath:/db/oracle/loading_temp_tables_oracle.sql"/> - <jdbc:script location="classpath:/db/oracle/users_oracle.sql"/> - <jdbc:script location="classpath:/db/oracle/clients_oracle.sql"/> - <jdbc:script location="classpath:/db/oracle/scopes_oracle.sql"/> - </jdbc:initialize-database>--> -</beans> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/server-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/server-config.xml deleted file mode 100644 index 544f01c98..000000000 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/server-config.xml +++ /dev/null @@ -1,77 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - Copyright 2018 The MIT Internet Trust Consortium - - Portions copyright 2011-2013 The MITRE Corporation - - 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. - --> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:mvc="http://www.springframework.org/schema/mvc" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:tx="http://www.springframework.org/schema/tx" - xmlns:context="http://www.springframework.org/schema/context" - xmlns:security="http://www.springframework.org/schema/security" - xmlns:oauth="http://www.springframework.org/schema/security/oauth2" - xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd - http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd - http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.2.xsd - http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd - http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd - http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> - - <bean id="configBean" class="org.mitre.openid.connect.config.ConfigurationPropertiesBean"> - - <!-- This property sets the root URL of the server, known as the issuer --> - <property name="issuer" value="http://localhost:8080/openid-connect-server-webapp/" /> - - <!-- This property is a URL pointing to a logo image 24px high to be used in the top bar --> - <property name="logoImageUrl" value="resources/images/openid_connect_small.png" /> - - <!-- This property sets the display name of the server, displayed in the topbar and page title --> - <property name="topbarTitle" value="OpenID Connect Server" /> - - <!-- This property sets the lifetime of registration access tokens, in seconds. Leave it unset (null) for no rotation. --> - <!-- <property name="regTokenLifeTime" value="172800" /> --> - - <!-- This property forces the issuer value to start with "https", recommended on production servers --> - <!-- <property name="forceHttps" value="true" /> --> - - <!-- This property sets the locale for server text --> - <!-- <property name="locale" value="sv" /> --> - - <!-- This property sets the set of namespaces for language translation files. The default is "messages". These are checked in the order presented here. --> - <!-- - <property name="languageNamespaces"> - <list> - <value>foo</value> - <value>bar</value> - <value>messages</value> - </list> - </property> - --> - - <!-- This property indicates if a dynamically registered client supports dual flows, such as client_credentials - at the same time with authorization_code or implicit --> - <!-- <property name="dualClient" value="true" /> --> - - <!-- This property turns on HEART compliance mode --> - <!-- <property name="heartMode" value="true" /> --> - - <!-- This property allows the server to create and accept fully-composed - user URIs (with the user-code emebedded) for the device flow --> - <!-- <property name="allowCompleteDeviceCodeUri" value="true" /> --> - - </bean> - -</beans> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/copyright.tag b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/copyright.tag deleted file mode 100644 index 4b0aa920a..000000000 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/copyright.tag +++ /dev/null @@ -1,4 +0,0 @@ -<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> -<c:if test="${ config.heartMode }"><span class="pull-left"><img src="resources/images/heart_mode.png" alt="HEART Mode" title="This server is running in HEART Compliance Mode" /></span> </c:if> -<spring:message code="copyright" arguments="${project.version}"/> diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/EndSessionEndpoint.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/web/EndSessionEndpoint.java deleted file mode 100644 index 26055501a..000000000 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/EndSessionEndpoint.java +++ /dev/null @@ -1,197 +0,0 @@ -/******************************************************************************* - * Copyright 2018 The MIT Internet Trust Consortium - * - * 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 org.mitre.openid.connect.web; - -import java.text.ParseException; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.mitre.jwt.assertion.AssertionValidator; -import org.mitre.jwt.assertion.impl.SelfAssertionValidator; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.service.UserInfoService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.common.exceptions.InvalidClientException; -import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -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.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; -import org.springframework.web.util.UriUtils; - -import com.google.common.base.Strings; -import com.google.common.collect.Iterables; -import com.nimbusds.jwt.JWT; -import com.nimbusds.jwt.JWTClaimsSet; -import com.nimbusds.jwt.JWTParser; - -/** - * Implementation of the End Session Endpoint from OIDC session management - * - * @author jricher - * - */ -@Controller -public class EndSessionEndpoint { - - public static final String URL = "endsession"; - - private static final String CLIENT_KEY = "client"; - private static final String STATE_KEY = "state"; - private static final String REDIRECT_URI_KEY = "redirectUri"; - - private static Logger logger = LoggerFactory.getLogger(EndSessionEndpoint.class); - - @Autowired - private SelfAssertionValidator validator; - - @Autowired - private UserInfoService userInfoService; - - @Autowired - private ClientDetailsEntityService clientService; - - @RequestMapping(value = "/" + URL, method = RequestMethod.GET) - public String endSession(@RequestParam (value = "id_token_hint", required = false) String idTokenHint, - @RequestParam (value = "post_logout_redirect_uri", required = false) String postLogoutRedirectUri, - @RequestParam (value = STATE_KEY, required = false) String state, - HttpServletRequest request, - HttpServletResponse response, - HttpSession session, - Authentication auth, Model m) { - - // conditionally filled variables - JWTClaimsSet idTokenClaims = null; // pulled from the parsed and validated ID token - ClientDetailsEntity client = null; // pulled from ID token's audience field - - if (!Strings.isNullOrEmpty(postLogoutRedirectUri)) { - session.setAttribute(REDIRECT_URI_KEY, postLogoutRedirectUri); - } - if (!Strings.isNullOrEmpty(state)) { - session.setAttribute(STATE_KEY, state); - } - - // parse the ID token hint to see if it's valid - if (!Strings.isNullOrEmpty(idTokenHint)) { - try { - JWT idToken = JWTParser.parse(idTokenHint); - - if (validator.isValid(idToken)) { - // we issued this ID token, figure out who it's for - idTokenClaims = idToken.getJWTClaimsSet(); - - String clientId = Iterables.getOnlyElement(idTokenClaims.getAudience()); - - client = clientService.loadClientByClientId(clientId); - - // save a reference in the session for us to pick up later - //session.setAttribute("endSession_idTokenHint_claims", idTokenClaims); - session.setAttribute(CLIENT_KEY, client); - } - } catch (ParseException e) { - // it's not a valid ID token, ignore it - logger.debug("Invalid id token hint", e); - } catch (InvalidClientException e) { - // couldn't find the client, ignore it - logger.debug("Invalid client", e); - } - } - - // are we logged in or not? - if (auth == null || !request.isUserInRole("ROLE_USER")) { - // we're not logged in anyway, process the final redirect bits if needed - return processLogout(null, request, response, session, auth, m); - } else { - // we are logged in, need to prompt the user before we log out - - // see who the current user is - UserInfo ui = userInfoService.getByUsername(auth.getName()); - - if (idTokenClaims != null) { - String subject = idTokenClaims.getSubject(); - // see if the current user is the same as the one in the ID token - // TODO: should we do anything different in these cases? - if (!Strings.isNullOrEmpty(subject) && subject.equals(ui.getSub())) { - // it's the same user - } else { - // it's not the same user - } - } - - m.addAttribute("client", client); - m.addAttribute("idToken", idTokenClaims); - - // display the log out confirmation page - return "logoutConfirmation"; - } - } - - @RequestMapping(value = "/" + URL, method = RequestMethod.POST) - public String processLogout(@RequestParam(value = "approve", required = false) String approved, - HttpServletRequest request, - HttpServletResponse response, - HttpSession session, - Authentication auth, Model m) { - - String redirectUri = (String) session.getAttribute(REDIRECT_URI_KEY); - String state = (String) session.getAttribute(STATE_KEY); - ClientDetailsEntity client = (ClientDetailsEntity) session.getAttribute(CLIENT_KEY); - - if (!Strings.isNullOrEmpty(approved)) { - // use approved, perform the logout - if (auth != null){ - new SecurityContextLogoutHandler().logout(request, response, auth); - } - SecurityContextHolder.getContext().setAuthentication(null); - // TODO: hook into other logout post-processing - } - - // if the user didn't approve, don't log out but hit the landing page anyway for redirect as needed - - - - // if we have a client AND the client has post-logout redirect URIs - // registered AND the URI given is in that list, then... - if (!Strings.isNullOrEmpty(redirectUri) && - client != null && client.getPostLogoutRedirectUris() != null) { - - if (client.getPostLogoutRedirectUris().contains(redirectUri)) { - // TODO: future, add the redirect URI to the model for the display page for an interstitial - // m.addAttribute("redirectUri", postLogoutRedirectUri); - - UriComponents uri = UriComponentsBuilder.fromHttpUrl(redirectUri).queryParam("state", state).build(); - - return "redirect:" + uri; - } - } - - // otherwise, return to a nice post-logout landing page - return "postLogout"; - } - -} diff --git a/openid-connect-server-webapp/.gitignore b/perun-oidc-server-webapp/.gitignore similarity index 100% rename from openid-connect-server-webapp/.gitignore rename to perun-oidc-server-webapp/.gitignore diff --git a/openid-connect-server-webapp/pom.xml b/perun-oidc-server-webapp/pom.xml similarity index 71% rename from openid-connect-server-webapp/pom.xml rename to perun-oidc-server-webapp/pom.xml index be9e63a13..8163fe1c4 100644 --- a/openid-connect-server-webapp/pom.xml +++ b/perun-oidc-server-webapp/pom.xml @@ -19,67 +19,30 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> - <groupId>org.mitre</groupId> - <artifactId>openid-connect-parent</artifactId> + <groupId>cz.muni.ics</groupId> + <artifactId>perun-oidc-parent</artifactId> <version>2.0.0</version> <relativePath>../pom.xml</relativePath> </parent> - <artifactId>openid-connect-server-webapp</artifactId> + <artifactId>perun-oidc-server-webapp</artifactId> <packaging>war</packaging> - <name>OpenID Connect Server Webapp</name> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <source>${java-version}</source> - <target>${java-version}</target> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-war-plugin</artifactId> - <configuration> - <warName>openid-connect-server-webapp</warName> - <webResources> - <resource> - <directory>src/main/webapp</directory> - <filtering>true</filtering> - <includes> - <include>**/*.tag</include> - <include>**/*.jsp</include> - </includes> - </resource> - <resource> - <directory>src/main/webapp</directory> - <filtering>false</filtering> - <excludes> - <exclude>**/*.tag</exclude> - <exclude>**/*.jsp</exclude> - </excludes> - </resource> - </webResources> - <packagingExcludes>less/**</packagingExcludes> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-dependency-plugin</artifactId> - <executions> - <execution> - <id>install</id> - <phase>install</phase> - <goals> - <goal>sources</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> + <properties> + <config.location>/etc/perun</config.location> + <log.to>FILE</log.to> + <log.contextName>oidc</log.contextName> + <log.facility>LOCAL7</log.facility> + <log.level>info</log.level> + <!--suppress UnresolvedMavenProperty --> + <log.rolling-file>${catalina.base}/logs/${CONTEXT_NAME}</log.rolling-file> + <!--suppress UnresolvedMavenProperty --> + <log.file>${catalina.base}/logs/${CONTEXT_NAME}</log.file> + <log.trace.file-extension>trace</log.trace.file-extension> + <log.file-extension>log</log.file-extension> + <log.times.file-extension>times</log.times.file-extension> + <final.name>oidc</final.name> + </properties> <dependencies> <dependency> @@ -112,7 +75,78 @@ <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </dependency> + <dependency> + <groupId>cz.muni.ics</groupId> + <artifactId>perun-oidc-server</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.security.extensions</groupId> + <artifactId>spring-security-saml2-core</artifactId> + </dependency> </dependencies> - <description>Deployable package of the OpenID Connect server</description> + <build> + <finalName>${final.name}</finalName> + <resources> + <resource> + <directory>src/main/resources</directory> + <filtering>true</filtering> + <includes> + <include>logback.xml</include> + <include>**/*</include> + </includes> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>${java-version}</source> + <target>${java-version}</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <configuration> + <warName>openid-connect-server-webapp</warName> + <webResources> + <resource> + <directory>src/main/webapp</directory> + <filtering>true</filtering> + <includes> + <include>**/*.tag</include> + <include>**/*.jsp</include> + <include>WEB-INF/user-context.xml</include> + </includes> + </resource> + <resource> + <directory>src/main/webapp</directory> + <filtering>false</filtering> + <excludes> + <exclude>**/*.tag</exclude> + <exclude>**/*.jsp</exclude> + </excludes> + </resource> + </webResources> + <packagingExcludes>less/**</packagingExcludes> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>install</id> + <phase>install</phase> + <goals> + <goal>sources</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </project> diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/clients.sql b/perun-oidc-server-webapp/src/main/resources/db/hsql/clients.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/hsql/clients.sql rename to perun-oidc-server-webapp/src/main/resources/db/hsql/clients.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_index.sql b/perun-oidc-server-webapp/src/main/resources/db/hsql/hsql_database_index.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_index.sql rename to perun-oidc-server-webapp/src/main/resources/db/hsql/hsql_database_index.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql b/perun-oidc-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql rename to perun-oidc-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/loading_temp_tables.sql b/perun-oidc-server-webapp/src/main/resources/db/hsql/loading_temp_tables.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/hsql/loading_temp_tables.sql rename to perun-oidc-server-webapp/src/main/resources/db/hsql/loading_temp_tables.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/scopes.sql b/perun-oidc-server-webapp/src/main/resources/db/hsql/scopes.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/hsql/scopes.sql rename to perun-oidc-server-webapp/src/main/resources/db/hsql/scopes.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/security-schema.sql b/perun-oidc-server-webapp/src/main/resources/db/hsql/security-schema.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/hsql/security-schema.sql rename to perun-oidc-server-webapp/src/main/resources/db/hsql/security-schema.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/users.sql b/perun-oidc-server-webapp/src/main/resources/db/hsql/users.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/hsql/users.sql rename to perun-oidc-server-webapp/src/main/resources/db/hsql/users.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/clients.sql b/perun-oidc-server-webapp/src/main/resources/db/mysql/clients.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/mysql/clients.sql rename to perun-oidc-server-webapp/src/main/resources/db/mysql/clients.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_index.sql b/perun-oidc-server-webapp/src/main/resources/db/mysql/mysql_database_index.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_index.sql rename to perun-oidc-server-webapp/src/main/resources/db/mysql/mysql_database_index.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_tables.sql b/perun-oidc-server-webapp/src/main/resources/db/mysql/mysql_database_tables.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_tables.sql rename to perun-oidc-server-webapp/src/main/resources/db/mysql/mysql_database_tables.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/scopes.sql b/perun-oidc-server-webapp/src/main/resources/db/mysql/scopes.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/mysql/scopes.sql rename to perun-oidc-server-webapp/src/main/resources/db/mysql/scopes.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/security-schema.sql b/perun-oidc-server-webapp/src/main/resources/db/mysql/security-schema.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/mysql/security-schema.sql rename to perun-oidc-server-webapp/src/main/resources/db/mysql/security-schema.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/users.sql b/perun-oidc-server-webapp/src/main/resources/db/mysql/users.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/mysql/users.sql rename to perun-oidc-server-webapp/src/main/resources/db/mysql/users.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/clients_oracle.sql b/perun-oidc-server-webapp/src/main/resources/db/oracle/clients_oracle.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/oracle/clients_oracle.sql rename to perun-oidc-server-webapp/src/main/resources/db/oracle/clients_oracle.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/create_db-user b/perun-oidc-server-webapp/src/main/resources/db/oracle/create_db-user similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/oracle/create_db-user rename to perun-oidc-server-webapp/src/main/resources/db/oracle/create_db-user diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/entity-mappings_oracle.xml b/perun-oidc-server-webapp/src/main/resources/db/oracle/entity-mappings_oracle.xml similarity index 84% rename from openid-connect-server-webapp/src/main/resources/db/oracle/entity-mappings_oracle.xml rename to perun-oidc-server-webapp/src/main/resources/db/oracle/entity-mappings_oracle.xml index 2aba62824..1578a9de6 100644 --- a/openid-connect-server-webapp/src/main/resources/db/oracle/entity-mappings_oracle.xml +++ b/perun-oidc-server-webapp/src/main/resources/db/oracle/entity-mappings_oracle.xml @@ -20,7 +20,7 @@ <description>OpenID Connect Server entities</description> - <entity class="org.mitre.oauth2.model.AuthenticationHolderEntity" name="AuthenticationHolderEntity"> + <entity class="cz.muni.ics.oauth2.model.AuthenticationHolderEntity" name="AuthenticationHolderEntity"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -33,7 +33,7 @@ <collection-table name="auth_holder_authority"> <join-column name="owner_id"/> </collection-table> - <convert converter="org.mitre.oauth2.model.convert.SimpleGrantedAuthorityStringConverter"/> + <convert converter="cz.muni.ics.oauth2.model.convert.SimpleGrantedAuthorityStringConverter"/> <column name="authority"/> </element-collection> <!-- table name too long: authentication_holder_resource_id --> @@ -57,7 +57,7 @@ </collection-table> <column name="val"/> <map-key-column name="extension"/> - <convert converter="org.mitre.oauth2.model.convert.SerializableStringConverter"/> + <convert converter="cz.muni.ics.oauth2.model.convert.SerializableStringConverter"/> </element-collection> <!-- table name too long: authentication_holder_request_parameter --> <element-collection fetch="EAGER" name="requestParameters"> @@ -70,7 +70,7 @@ </attributes> </entity> - <entity class="org.mitre.oauth2.model.AuthorizationCodeEntity" name="AuthorizationCodeEntity"> + <entity class="cz.muni.ics.oauth2.model.AuthorizationCodeEntity" name="AuthorizationCodeEntity"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -81,7 +81,7 @@ </attributes> </entity> - <entity class="org.mitre.oauth2.model.ClientDetailsEntity" name="ClientDetailsEntity"> + <entity class="cz.muni.ics.oauth2.model.ClientDetailsEntity" name="ClientDetailsEntity"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -92,27 +92,27 @@ <!-- column name too long: user_info_encrypted_response_alg --> <basic name="userInfoEncryptedResponseAlg"> <column name="user_info_encrypted_resp_alg"/> - <convert converter="org.mitre.oauth2.model.convert.JWEAlgorithmStringConverter"/> + <convert converter="cz.muni.ics.oauth2.model.convert.JWEAlgorithmStringConverter"/> </basic> <!-- column name too long: user_info_encrypted_response_enc --> <basic name="userInfoEncryptedResponseEnc"> <column name="user_info_encrypted_resp_enc"/> - <convert converter="org.mitre.oauth2.model.convert.JWEEncryptionMethodStringConverter"/> + <convert converter="cz.muni.ics.oauth2.model.convert.JWEEncryptionMethodStringConverter"/> </basic> <!-- column name too long: id_token_encrypted_response_alg --> <basic name="idTokenEncryptedResponseAlg"> <column name="id_token_encrypted_resp_alg"/> - <convert converter="org.mitre.oauth2.model.convert.JWEAlgorithmStringConverter"/> + <convert converter="cz.muni.ics.oauth2.model.convert.JWEAlgorithmStringConverter"/> </basic> <!-- column name too long: id_token_encrypted_response_enc --> <basic name="idTokenEncryptedResponseEnc"> <column name="id_token_encrypted_resp_enc"/> - <convert converter="org.mitre.oauth2.model.convert.JWEEncryptionMethodStringConverter"/> + <convert converter="cz.muni.ics.oauth2.model.convert.JWEEncryptionMethodStringConverter"/> </basic> <!-- column name too long: token_endpoint_auth_signing_alg --> <basic name="tokenEndpointAuthSigningAlg"> <column name="token_endpoint_auth_sign_alg"/> - <convert converter="org.mitre.oauth2.model.convert.JWSAlgorithmStringConverter"/> + <convert converter="cz.muni.ics.oauth2.model.convert.JWSAlgorithmStringConverter"/> </basic> <!-- table name too long: client_post_logout_redirect_uri --> <element-collection fetch="EAGER" name="postLogoutRedirectUris"> @@ -124,7 +124,7 @@ </attributes> </entity> - <entity class="org.mitre.oauth2.model.OAuth2AccessTokenEntity" name="OAuth2AccessTokenEntity"> + <entity class="cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity" name="OAuth2AccessTokenEntity"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -135,7 +135,7 @@ </attributes> </entity> - <entity class="org.mitre.oauth2.model.OAuth2RefreshTokenEntity" name="OAuth2RefreshTokenEntity"> + <entity class="cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity" name="OAuth2RefreshTokenEntity"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -146,7 +146,7 @@ </attributes> </entity> - <entity class="org.mitre.oauth2.model.SavedUserAuthentication" name="SavedUserAuthentication"> + <entity class="cz.muni.ics.oauth2.model.SavedUserAuthentication" name="SavedUserAuthentication"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -157,7 +157,7 @@ </attributes> </entity> - <entity class="org.mitre.oauth2.model.SystemScope" name="SystemScope"> + <entity class="cz.muni.ics.oauth2.model.SystemScope" name="SystemScope"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -168,7 +168,7 @@ </attributes> </entity> - <entity class="org.mitre.openid.connect.model.ApprovedSite" name="ApprovedSite"> + <entity class="cz.muni.ics.openid.connect.model.ApprovedSite" name="ApprovedSite"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -179,7 +179,7 @@ </attributes> </entity> - <entity class="org.mitre.openid.connect.model.BlacklistedSite" name="BlacklistedSite"> + <entity class="cz.muni.ics.openid.connect.model.BlacklistedSite" name="BlacklistedSite"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -190,7 +190,7 @@ </attributes> </entity> - <entity class="org.mitre.openid.connect.model.PairwiseIdentifier" name="PairwiseIdentifier"> + <entity class="cz.muni.ics.openid.connect.model.PairwiseIdentifier" name="PairwiseIdentifier"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -201,7 +201,7 @@ </attributes> </entity> - <entity class="org.mitre.openid.connect.model.WhitelistedSite" name="WhitelistedSite"> + <entity class="cz.muni.ics.openid.connect.model.WhitelistedSite" name="WhitelistedSite"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -212,7 +212,7 @@ </attributes> </entity> - <entity class="org.mitre.uma.model.Claim" name="Claim"> + <entity class="cz.muni.ics.uma.model.Claim" name="Claim"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -223,7 +223,7 @@ </attributes> </entity> - <entity class="org.mitre.uma.model.Permission" name="Permission"> + <entity class="cz.muni.ics.uma.model.Permission" name="Permission"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -234,7 +234,7 @@ </attributes> </entity> - <entity class="org.mitre.uma.model.PermissionTicket" name="PermissionTicket"> + <entity class="cz.muni.ics.uma.model.PermissionTicket" name="PermissionTicket"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -245,7 +245,7 @@ </attributes> </entity> - <entity class="org.mitre.uma.model.Policy" name="Policy"> + <entity class="cz.muni.ics.uma.model.Policy" name="Policy"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -256,7 +256,7 @@ </attributes> </entity> - <entity class="org.mitre.uma.model.ResourceSet" name="ResourceSet"> + <entity class="cz.muni.ics.uma.model.ResourceSet" name="ResourceSet"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -267,7 +267,7 @@ </attributes> </entity> - <entity class="org.mitre.uma.model.SavedRegisteredClient" name="SavedRegisteredClient"> + <entity class="cz.muni.ics.uma.model.SavedRegisteredClient" name="SavedRegisteredClient"> <attributes> <!-- changing generated value to sequence strategy (Oracle doesn't support identity) --> <id name="id"> @@ -278,4 +278,4 @@ </attributes> </entity> -</entity-mappings> \ No newline at end of file +</entity-mappings> diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/loading_temp_tables_oracle.sql b/perun-oidc-server-webapp/src/main/resources/db/oracle/loading_temp_tables_oracle.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/oracle/loading_temp_tables_oracle.sql rename to perun-oidc-server-webapp/src/main/resources/db/oracle/loading_temp_tables_oracle.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_index.sql b/perun-oidc-server-webapp/src/main/resources/db/oracle/oracle_database_index.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_index.sql rename to perun-oidc-server-webapp/src/main/resources/db/oracle/oracle_database_index.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_tables.sql b/perun-oidc-server-webapp/src/main/resources/db/oracle/oracle_database_tables.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_tables.sql rename to perun-oidc-server-webapp/src/main/resources/db/oracle/oracle_database_tables.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/scopes_oracle.sql b/perun-oidc-server-webapp/src/main/resources/db/oracle/scopes_oracle.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/oracle/scopes_oracle.sql rename to perun-oidc-server-webapp/src/main/resources/db/oracle/scopes_oracle.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/security-schema_oracle.sql b/perun-oidc-server-webapp/src/main/resources/db/oracle/security-schema_oracle.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/oracle/security-schema_oracle.sql rename to perun-oidc-server-webapp/src/main/resources/db/oracle/security-schema_oracle.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/users_oracle.sql b/perun-oidc-server-webapp/src/main/resources/db/oracle/users_oracle.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/oracle/users_oracle.sql rename to perun-oidc-server-webapp/src/main/resources/db/oracle/users_oracle.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/clients.sql b/perun-oidc-server-webapp/src/main/resources/db/psql/clients.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/psql/clients.sql rename to perun-oidc-server-webapp/src/main/resources/db/psql/clients.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_index.sql b/perun-oidc-server-webapp/src/main/resources/db/psql/psql_database_index.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/psql/psql_database_index.sql rename to perun-oidc-server-webapp/src/main/resources/db/psql/psql_database_index.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_tables.sql b/perun-oidc-server-webapp/src/main/resources/db/psql/psql_database_tables.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/psql/psql_database_tables.sql rename to perun-oidc-server-webapp/src/main/resources/db/psql/psql_database_tables.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/scopes.sql b/perun-oidc-server-webapp/src/main/resources/db/psql/scopes.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/psql/scopes.sql rename to perun-oidc-server-webapp/src/main/resources/db/psql/scopes.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/security-schema.sql b/perun-oidc-server-webapp/src/main/resources/db/psql/security-schema.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/psql/security-schema.sql rename to perun-oidc-server-webapp/src/main/resources/db/psql/security-schema.sql diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/users.sql b/perun-oidc-server-webapp/src/main/resources/db/psql/users.sql similarity index 100% rename from openid-connect-server-webapp/src/main/resources/db/psql/users.sql rename to perun-oidc-server-webapp/src/main/resources/db/psql/users.sql diff --git a/openid-connect-server-webapp/src/main/resources/keystore.jwks b/perun-oidc-server-webapp/src/main/resources/keystore.jwks similarity index 100% rename from openid-connect-server-webapp/src/main/resources/keystore.jwks rename to perun-oidc-server-webapp/src/main/resources/keystore.jwks diff --git a/perun-oidc-server-webapp/src/main/resources/localization/cs.properties b/perun-oidc-server-webapp/src/main/resources/localization/cs.properties new file mode 100644 index 000000000..bdd8ac27e --- /dev/null +++ b/perun-oidc-server-webapp/src/main/resources/localization/cs.properties @@ -0,0 +1,173 @@ +#CONSENT +yes=Ano, akceptuji +no=Ne, neakceptuji +login=Login +consent_privacy_policy=Zásady zpracování osobních údajů pro službu +consent_header=Obsah odesílaných osobních informací službě +consent_title=Obsah odesílaných osobních informací službě +remember=Příště se již neptat + +#APPROVE_DEVICE +device_approve_privacy=Bezpečnostní politika služby +device_approve_header=Schválení přístupu k Vašim datům +device_approve_title=Schválení přístupu k Vašim datům + +#DEVICE_APPROVED +device_approved_approved=Zařížení bylo autorizováno +device_approved_rejected=Zařízení byl odmítnut přístup +device_approved_title=Autorizace zařízení dokončena +device_approved_text_approved_start=Zařízení bylo úspěšně autorizováno. Nyní můžete pokračovat ke službě +device_approved_text_approved_end=na Vašem zařízení. Tahle stránka může být zavřena. +device_approved_text_rejected_start=Zařízení byl odmítnut přístup ke službě +device_approved_text_rejected_end=Jestli jste tak nechtěli učinit, zahajte proces autorizace od začátku. Tahle stránka může být zavřena. + + +#REQUEST USER CODE +request_code_title=Zadejte autorizační kód zařízení +request_code_header=Zadejte autorizační kód zařízení +user_code_empty_or_not_found=Nebyl zadán žádný kód anebo zadanej kód je nesprávný. +user_code_expired=Platnost použitého kódu vypršela. Prosíme, vyžádejte si nový a opakujte proces. +user_code_already_approved=Zadaný kód už byl použit. Prosíme, vyžádejte si nový a opakujte proces. +user_code_mismatch=Zadaný kód nebyl rozpoznán. Prosíme, ověřte že jste zadali správný kód. +user_code_error=Vyskytla se chyba pri zpracování Vašeho požadavku. Zkuste jej zopakovat. +user_code_submit=Pokračovat +user_code_info=Zadejte autorizační kód zobrazen na zařízení z kterého se snažíte přihlásit. +code=Kód + +#IsTestSpWarning +is_test_sp_warning_title=Varování - služba je testovací +is_test_sp_warning_header=Varování +is_test_sp_warning_text=Přistupujete ke službě, která je v testovacím režimu. +is_test_sp_warning_continue=Pokračovat + +#CLAIMS AND SCOPES +no_scopes=Žádné data nebudou odeslány +openid=Identifikátor uživatele na službě +sub=Identifikátor uživatele +profile=Profil uživatele +email=Email +address=Adresa +phone=Telefonní číslo +offline_access=Offline přístup +perun_api=Volání Perun API ve jménu uživatele +groupNames=Jména skupin ve kterých je uživatel členem +eduPersonEntitlement=Oprávnění +permissions_ega=Povolení pro EGA datasety +permissions_rems=Povolení pro REMS datasety +forwardedScopedAffiliations=Vztah k domovské(ým) organizaci(cím) +bona_fide_status=Bona fide status +country=Krajina +ga4gh=Global Alliance For Genomics and Health +eppns=Identifikátory osoby v organizaci +name=Jméno uživatele +preferred_username=Uživatelské jméno +given_name=Křestní jméno +middle_name=Střední jméno +family_name=Příjmení +locale=Jazyk +zoneinfo=Zóna +phone_number=Telefon + +#UNAPPROVED +contact_p=V případě nejasností nás kontaktujte na +403_header=Přístup odmítnut +403_text=Nemáte dostatečná práva pro přístup ke službě: +403_informationPage=Pro více informací o službě navštivte +403_contactSupport=Pokud si myslíte že máte mít přístup, kontaktujte administrátora: +403_subject=Problém s přihlášením do služby +403_isCesnetEligible_notSet_hdr=Přístup zamítnut +403_isCesnetEligible_notSet_msg=Přístup ke službě zamítnut, protože Váš účet není z české akademické instituce. Přihlaste se, prosím, pomocí svého účtu u akademické instituce.<br/><a class="mt-2 cw btn btn-primary btn-lg btn-block" href="%%TARGET%%">Znovu přihlásit</a> +403_isCesnetEligible_expired_hdr=Přístup zamítnut +403_isCesnetEligible_expired_msg=Přístup ke službě zamítnut, protože plynula doba 12 měsíců od Vašeho posledního přihlášení účtem z české akademické instituce. Přihlaste se, prosím, pomocí svého účtu u akademické instituce.<br/><a class="mt-2 cw btn btn-lg btn-primary btn-block" href="%%TARGET%%">Znovu přihlásit</a> +403_ensure_vo_hdr=Přístup zamítnut +403_ensure_vo_msg=Nemáte dostatečná práva pro přístup ke službě +403_authorization_hdr=Přístup zamítnut +403_authorization_msg=Tato stránka se Vám zobrazuje, protože nemáte přístup ke službě. To může být důsledkem přístupových omezení nastavených administrátorem. +403_not_in_test_vos_groups_hdr=Přístup zamítnut +403_not_in_test_vos_groups_msg=Tato stránka se Vám zobrazuje, protože nemáte přístup k testovacím službám AAI. +403_not_in_prod_vos_groups_hdr=Přístup zamítnut +403_not_in_prod_vos_groups_msg=Tato stránka se Vám zobrazuje, protože nemáte přístup ke službám AAI. +403_not_in_mandatory_vos_groups_hdr=Přístup zamítnut +403_not_in_mandatory_vos_groups_msg=Tato stránka se Vám zobrazuje, protože Vaše požadované členství v organizaci je nevalidní. +403_not_logged_in_hdr=Přístup zamítnut +403_not_logged_in_msg=Zdá se, že přihlášení selhalo. Zkuste, prosím, zavřít Váš prohlížeč a přihlásit se znovu. + +#GO TO REGISTRATION +go_to_registration_title=Je vyžadována Vaše aktivita +go_to_registration_header1=Pro přístup ke službě +go_to_registration_header2=je vyžadována Vaše aktivita +go_to_registration_continue=Pokračovat na stránku s doplňujícími informacemi + +#REGISTRATION +registration_title=Registrace pro přístup ke službě +registration_header1=Přístup ke službě +registration_header2=byl zamítnut +registration_message=Pro získání přístupu k dané službě je nutné být členem jedné z následujících skupin. Pokračujte výběrem příslušné organizace a skupiny. +registration_select_vo=Vyberte virtuální organizaci: +registration_select_group=Vyberte skupinu pro registraci: +registration_continue=Pokračovat na registrační stránku do vybrané skupiny + +#CESNET footer specific +footer_other_projects=OSTATNÍ PROJEKTY +footer_helpdesk=HELPDESK + +#AUP +aup_header=Formulář s podmínkami užití +must_agree_aup=Pro pokračování musíte souhlasit s následujícími podmínkami užití: +org_vo=Organizace / Virtuální Organizace +see_aup=Prohlédněte si podmínky užití ve verzi +here=zde. +agree_aup=Souhlasím s podmínkami užití + +#MUNI header specific +unif_login="Přihlášení na MU" +go_to_login_title=Přejít k přihlášení (Klávesová zkratka: Alt + 2) +go_to_login_text=Přejít k přihlášení +language=Česky +img_name=sso +img_width=180 +img_height=34 +other_lang=en +other_language=English +muni_logo=MUNI Jednotné přihlášení + +#MUNI footer specific +masaryk_university=© Masarykova univerzita +service=Službu +unified_login=Jednotné přihlášení na MU +provided=zajišťuje +ics=Ústav výpočetní techniky MU + +#Logout +logout.confirmation.submit=Odhlásit +logout.confirmation.deny=Zůstat přihlášen(a) +logout.confirmation.header=Potvrzení odhlášení +logout.confirmation.explanation=Skutečně se chcete odhlásit od poskytovatele identity? + +#Continue in ensure_vo +continue_direct_title=Přesměrování na registraci +continue_direct_header=Budete přesměrován(a) +continue_direct_heading=Zaregistrujte se pro získaní přístupu +continue_direct_text=Nemáte dostatečná oprávnení po přístup ke službě. Kliknutím na tlačítko níže, budete přesměrován(a) na registraci pro získání přístupu. +continue_direct_btn=Pokračovat + +# SAML Logout Success (/logout_success) +logout_success_title=Odhlášení proběhlo úspěšně +logout_success_header=Odhlášení proběhlo úspěšně +logout_success_msg=Byl(a) jste úspěšně odhlášen(a). + +# SAML Login Failure (/login_failure) +login_failure_title=Problém s přihlášením +login_failure_header=Problém s přihlášením +login_failure_msg=Ups! Zdá se, že jsme Vás nemohli přihlásit. Zkuste to znovu. +login_failure_contact_us=Pokud problém přetrvává, kontaktuje nás na + +# SAML Login Success (/login_success) +login_success_title=Přihlášení proběhlo úspěšně +login_success_header=Přihlášení proběhlo úspěšně +login_success_msg=Byl(a) jste úspěšně přihlášen(a), avšak neregistrujeme žádnou službu, na kterou jste se pokoušel(a) přistoupit. + +# Logout denied (endsession endpoint with clicking NO) +logout_denied_title=Odhlášení zrušeno +logout_denied_header=Odhlášení zrušeno +logout_denied_msg=Proces odhlášení byl zastaven. diff --git a/perun-oidc-server-webapp/src/main/resources/localization/en.properties b/perun-oidc-server-webapp/src/main/resources/localization/en.properties new file mode 100644 index 000000000..be19a55ef --- /dev/null +++ b/perun-oidc-server-webapp/src/main/resources/localization/en.properties @@ -0,0 +1,172 @@ +#CONSENT +yes=Yes, continue +no=No, cancel +login=login +consent_privacy_policy=Privacy policy for the service +consent_header=Consent about releasing personal information to service +consent_title=Consent about releasing personal information to service +remember=Do not ask again + +#APPROVE_DEVICE +device_approve_privacy=Privacy policy for the service +device_approve_header=Approve device to access your data +device_approve_title=Approve device to access your data + +#DEVICE_APPROVED +device_approved_approved=The device has been authorized. +device_approved_rejected=The device has been rejected authorization. +device_approved_title=Device approval result +device_approved_text_approved_start=The device has been successfully authorized. You can now access the service +device_approved_text_approved_end=on your device. You may now close this page. +device_approved_text_rejected_start=The device has been denied access to the service +device_approved_text_rejected_end=If you did not intend to do this, start the authorization process again. You may now close this page. + +#REQUEST USER CODE +request_code_title=Enter the device authorization code +request_code_header=Enter the device authorization code +user_code_empty_or_not_found=No authorization code has been provided or it has not been recognized. +user_code_expired=The authorization code you have used has expired. Please request a new one and restart the process. +user_code_already_approved=The authorization code you have used has been already used. Please request a new one and restart the process. +user_code_mismatch=The code you have used has not been recognized. Please verify your input. +user_code_error=An error has occurred while processing your request. Please try it again. +user_code_submit=Submit +user_code_info=Enter the code displayed on the device you are trying to authenticate on. +code=Code + +#IsTestSpWarning +is_test_sp_warning_title=Warning - test service +is_test_sp_warning_header=Warning +is_test_sp_warning_text=You are about to access service, which is in testing environment. +is_test_sp_warning_continue=Continue + + +#CLAIMS AND SCOPES +no_scopes=No data will be released +sub=Identifier of user +openid=Identifier of user on a service +profile=Profile +email=Email +address=Adress +phone=Phone number +offline_access=Offline access +perun_api=Calls to Perun API in the name of user +groupNames=Names of groups that user is member of +eduPersonEntitlement=Entitlement +permissions_ega=Permissions for EGA datasets +permissions_rems=Permissions for REMS datasets +forwardedScopedAffiliations=Home organization affiliation +bona_fide_status=Bona fide status +country=Country +eppns=Person principal names +name=Name of user +preferred_username=Username +given_name=Given name +middle_name=Middle name +family_name=Family name +locale=Language +zoneinfo=Zone +phone_number=Phone + +#UNAPPROVED +contact_p=In case of any questions, do not hesitate to contact us at +403_header=Access forbidden +403_text=You don't meet the prerequisites for accessing the service: +403_informationPage=For more information about this service please visit this +403_contactSupport=If you think you should have an access contact service operator at +403_subject=Problem with login to service: +403_isCesnetEligible_notSet_hdr=Access denied +403_isCesnetEligible_notSet_msg=Your account is not from Czech academic institution. Please log in with your account from academic institution.<a class="mt-2 cw btn btn-primary btn-lg btn-block" href="%%TARGET%%">Log in again</a> +403_isCesnetEligible_expired_hdr=Access denied +403_isCesnetEligible_expired_msg=Your last login, from Czech academic institution, has been registered 12 months ago. Please sign in with your account from academic institution.<a class="mt-2 cw btn btn-primary btn-lg btn-block" href="%%TARGET%%">Log in again</a> +403_ensure_vo_hdr=Access denied +403_ensure_vo_msg=You don't meet the prerequisites to access the service. +403_authorization_hdr=Access denied +403_authorization_msg=You see this page because you are not allowed to access the service. This situation can be a result of the access restrictions that the service administrator has set up. +403_not_in_test_vos_groups_hdr=Access denied +403_not_in_test_vos_groups_msg=You see this page because you are not allowed to access AAI's testing services. +403_not_in_prod_vos_groups_hdr=Access denied +403_not_in_prod_vos_groups_msg=You see this page because you are not allowed to access AAI's services. +403_not_in_mandatory_vos_groups_hdr=Access denied +403_not_in_mandatory_vos_groups_msg=You are seeing this page because your membership in the required organizational units is invalid. +403_not_logged_in_hdr=Access denied +403_not_logged_in_msg=It appears the login process has failed. Please close your browser and try to log in again. + +#GO TO REGISTRATION +go_to_registration_title=Your activity is necessary +go_to_registration_header1=Your activity is necessary to access the +go_to_registration_header2=service +go_to_registration_continue=Continue to a page with additional information + +#REGISTRATION +registration_title=Registration for access to the service +registration_header1=Access to the service +registration_header2=has been forbidden +registration_message=To access the service it is necessary to have a valid membership in one of the following groups. Please proceed with selection of organization and group for registration. +registration_select_vo=Select virtual organization for registration: +registration_select_group=Select group for registration: +registration_continue=Continue to the registration page for selected group + +#CESNET footer specific +footer_other_projects=OTHER CESNET PROJECTS +footer_helpdesk=HELPDESK + +#AUP +aup_header=Acceptable Usage Policy form +must_agree_aup=You must agree to the following acceptable usage policies: +org_vo=Organization / Virtual Organization +see_aup=See the acceptable usage policy in version +here=here. +agree_aup=I agree with the acceptable usage policy + +#MUNI header specific +unif_login=Unified MU login +go_to_login_title=Go to login (Shortcut: Alt + 2) +go_to_login_text=Go to login +language=English +img_name=sso-en +img_width=160 +img_height=35 +other_lang=cs +other_language=Česky +muni_logo=MUNI Unified login + +#MUNI footer specific +masaryk_university=© Masaryk University +service=The service +unified_login=Unified MU login +provided=is provided by +ics=Institute of Computer Science + +#Logout +logout.confirmation.submit=Log Out +logout.confirmation.deny=Stay Logged In +logout.confirmation.header=Confirm logout +logout.confirmation.explanation=Do you want to log out of the identity provider? + +#Continue in ensure_vo +continue_direct_title=Redirect to registration +continue_direct_header=You will be redirected +continue_direct_heading=Register to get access +continue_direct_text=You don't meet the prerequisites to access the service. By clicking the button below, you will be redirected to a registration page, where you can apply for access. +continue_direct_btn=Continue + +# SAML Logout Success (/logout_success) +logout_success_title=Logout success +logout_success_header=Logout success +logout_success_msg=You have been successfully logged out. + +# SAML Login Failure (/login_failure) +login_failure_title=Login failure +login_failure_header=Login error +login_failure_msg=Ooops! It seems like an error during the login. Please try to log in again. +login_failure_contact_us=If the problem persists, contact us at + +# SAML Login Success (/login_success) +login_success_title=Login success +login_success_header=Login success +login_success_msg=You have successfully logged in. However, it seems we have no service to forward you to. + +# Logout denied (endsession endpoint with clicking NO) +logout_denied_title=Logout denied +logout_denied_header=Logout canceled +logout_denied_msg=You have canceled the logout process. diff --git a/openid-connect-server-webapp/src/main/resources/log4j.xml b/perun-oidc-server-webapp/src/main/resources/log4j.xml similarity index 88% rename from openid-connect-server-webapp/src/main/resources/log4j.xml rename to perun-oidc-server-webapp/src/main/resources/log4j.xml index efb4074fe..3293dcfd4 100644 --- a/openid-connect-server-webapp/src/main/resources/log4j.xml +++ b/perun-oidc-server-webapp/src/main/resources/log4j.xml @@ -32,28 +32,28 @@ </appender> <!-- Application Loggers --> - <logger name="org.mitre.openid"> + <logger name="cz.muni.ics.openid"> <level value="info" /> </logger> - <logger name="org.mitre.oauth2"> + <logger name="cz.muni.ics.oauth2"> <level value="info" /> </logger> - <logger name="org.mitre.discovery"> + <logger name="cz.muni.ics.discovery"> <level value="info" /> </logger> - <logger name="org.mitre.jose"> + <logger name="cz.muni.ics.jose"> <level value="info" /> </logger> - <logger name="org.mitre.jwt"> + <logger name="cz.muni.ics.jwt"> <level value="info" /> </logger> - <logger name="org.mitre.util"> + <logger name="cz.muni.ics.util"> <level value="info" /> </logger> - <logger name="org.mitre.uma"> + <logger name="cz.muni.ics.uma"> <level value="info" /> </logger> - <logger name="org.mitre.data"> + <logger name="cz.muni.ics.data"> <level value="info" /> </logger> diff --git a/perun-oidc-server-webapp/src/main/resources/logback.xml b/perun-oidc-server-webapp/src/main/resources/logback.xml new file mode 100644 index 000000000..30fe672a2 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/resources/logback.xml @@ -0,0 +1,58 @@ +<configuration packagingData="true" debug="false" scan="false" scanPeriod="30 seconds"> + <contextName>${log.contextName}</contextName> + <property name="PATTERN" + value='%d{"yyyy-MM-dd HH:mm:ss.SSS"} %X{remoteAddr} [%X{sessionID}]: %-5level %logger{40} - %m%n%xException'/> + <property name="PATTERN_SYSLOG" + value='%X{remoteAddr} [%X{sessionID}] %cn: %-5level %logger{40} - %m%n%xException'/> + + <!-- ROLLING FILE --> + <appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.rolling-file}.${log.file-extension}</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${log.rolling-file}.${log.file-extension}.%d{yyyy-MM-dd}</fileNamePattern> + </rollingPolicy> + <encoder> + <pattern>${PATTERN}</pattern> + </encoder> + </appender> + + <!-- FILE --> + <appender name="FILE" class="ch.qos.logback.core.FileAppender"> + <file>${log.file}.${log.file-extension}</file> + <encoder> + <pattern>${PATTERN}</pattern> + </encoder> + </appender> + + <!-- SYSLOG --> + <appender name="SYSLOG" class="ch.qos.logback.classic.net.SyslogAppender"> + <!-- PASSED FROM POM.XML / MAVEN BUILD PROPS --> + <facility>${log.facility}</facility> + <throwableExcluded>true</throwableExcluded> + <suffixPattern>${PATTERN_SYSLOG}</suffixPattern> + </appender> + + <root level="${log.level}"> + <appender-ref ref="${log.to}"/> + </root> + + <!-- keep Spring quiet --> + <logger name="org.springframework" level="warn"/> + <logger name="org.springframework.security.core.SpringSecurityCoreVersion" level="info"/> + <logger name="cz.muni.ics.openid.connect.config.JsonMessageSource" level="warn"/> + <logger name="org.apache" level="warn"/> + <logger name="org.apache.directory" level="warn"/> + <logger name="org.apache.directory.ldap.client.api.LdapNetworkConnection" level="error"/> + <logger name="com.zaxxer.hikari" level="warn"/> + <logger name="cz.muni.ics" level="info"/> + <logger name="org.opensaml" level="info"/> + <logger name="org.springframework.security.saml" level="debug"/> + <logger name="PROTOCOL_MESSAGE" level="warn"/> + <!-- PASSED FROM POM.XML / MAVEN BUILD PROPS --> + <logger name="cz.muni.ics.oidc" level="${log.level}"/> + <logger name="cz.muni.ics.oidc.aop.WebLoggingAspect" level="debug"/> + <logger name="cz.muni.ics.oidc.aop.ExecutionTimeLoggingAspect" level="trace"/> + <logger name="cz.muni.ics.openid.connect.web.EndSessionEndpoint" level="${log.level}"/> + <logger name="net.javacrumbs.shedlock" level="error"/> + +</configuration> diff --git a/perun-oidc-server-webapp/src/main/resources/web_classes/web_html_classes.properties b/perun-oidc-server-webapp/src/main/resources/web_classes/web_html_classes.properties new file mode 100644 index 000000000..d5fa0d22d --- /dev/null +++ b/perun-oidc-server-webapp/src/main/resources/web_classes/web_html_classes.properties @@ -0,0 +1,4 @@ +perun-attrname.h2.class=h4 oh mb-0 mt-0 +perun-attrname.label.class=h4 mb-0 mt-0 +perun-attrcontainer.ul.class= +perun-attrlist.h3.class=h5 mb-0 mt-0 \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/META-INF/MANIFEST.MF b/perun-oidc-server-webapp/src/main/webapp/META-INF/MANIFEST.MF similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/META-INF/MANIFEST.MF rename to perun-oidc-server-webapp/src/main/webapp/META-INF/MANIFEST.MF diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/application-context.xml similarity index 76% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/application-context.xml index ed566e002..dae4f464f 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/application-context.xml @@ -33,7 +33,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- Scan for components --> - <context:component-scan annotation-config="true" base-package="org.mitre" /> + <context:component-scan annotation-config="true" base-package="cz.muni.ics" /> <!-- Enables the Spring MVC @Controller programming model --> <tx:annotation-driven transaction-manager="transactionManager" /> @@ -44,23 +44,23 @@ </mvc:message-converters> </mvc:annotation-driven> - <bean id="userInfoInterceptor" class="org.mitre.openid.connect.web.UserInfoInterceptor" /> - <bean id="serverConfigInterceptor" class="org.mitre.openid.connect.web.ServerConfigInterceptor" /> + <bean id="userInfoInterceptor" class="cz.muni.ics.openid.connect.web.UserInfoInterceptor" /> + <bean id="serverConfigInterceptor" class="cz.muni.ics.openid.connect.web.ServerConfigInterceptor" /> <mvc:interceptors> <mvc:interceptor> <!-- Exclude APIs and other machine-facing endpoints from these interceptors --> <mvc:mapping path="/**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.openid.connect.web.JWKSetPublishingEndpoint).URL}**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.JWKSetPublishingEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" /> <mvc:exclude-mapping path="/resources/**" /> <mvc:exclude-mapping path="/token**"/> - <mvc:exclude-mapping path="/#{T(org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint).URL}/**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.openid.connect.web.ProtectedResourceRegistrationEndpoint).URL}/**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.openid.connect.web.UserInfoEndpoint).URL}**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.openid.connect.web.RootController).API_URL}/**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.oauth2.web.DeviceEndpoint).URL}/**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.oauth2.web.IntrospectionEndpoint).URL}**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.oauth2.web.RevocationEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.DynamicClientRegistrationEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.ProtectedResourceRegistrationEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.UserInfoEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.RootController).API_URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.DeviceEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.IntrospectionEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.RevocationEndpoint).URL}**" /> <!-- Inject the UserInfo into the response --> <ref bean="userInfoInterceptor"/> @@ -68,17 +68,17 @@ <mvc:interceptor> <!-- Exclude APIs and other machine-facing endpoints from these interceptors --> <mvc:mapping path="/**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.openid.connect.web.JWKSetPublishingEndpoint).URL}**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.JWKSetPublishingEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" /> <mvc:exclude-mapping path="/resources/**" /> <mvc:exclude-mapping path="/token**"/> - <mvc:exclude-mapping path="/#{T(org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint).URL}/**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.openid.connect.web.ProtectedResourceRegistrationEndpoint).URL}/**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.openid.connect.web.UserInfoEndpoint).URL}**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.openid.connect.web.RootController).API_URL}/**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.oauth2.web.DeviceEndpoint).URL}/**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.oauth2.web.IntrospectionEndpoint).URL}**" /> - <mvc:exclude-mapping path="/#{T(org.mitre.oauth2.web.RevocationEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.DynamicClientRegistrationEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.ProtectedResourceRegistrationEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.UserInfoEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.RootController).API_URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.DeviceEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.IntrospectionEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.RevocationEndpoint).URL}**" /> <!-- Inject the server configuration into the response --> <ref bean="serverConfigInterceptor"/> </mvc:interceptor> @@ -102,7 +102,7 @@ <oauth:web-expression-handler id="oauthWebExpressionHandler" /> - <bean id="mdcFilter" class="org.mitre.mdc.MultiMDCFilter"/> + <bean id="mdcFilter" class="cz.muni.ics.mdc.MultiMDCFilter"/> <!-- Spring Security configuration --> @@ -127,14 +127,14 @@ </security:http> <!-- Allow open access to discovery endpoints --> - <security:http pattern="/#{T(org.mitre.openid.connect.web.JWKSetPublishingEndpoint).URL}**" use-expressions="true" entry-point-ref="http403EntryPoint" create-session="stateless"> - <security:intercept-url pattern="/#{T(org.mitre.openid.connect.web.JWKSetPublishingEndpoint).URL}**" access="permitAll"/> + <security:http pattern="/#{T(cz.muni.ics.openid.connect.web.JWKSetPublishingEndpoint).URL}**" use-expressions="true" entry-point-ref="http403EntryPoint" create-session="stateless"> + <security:intercept-url pattern="/#{T(cz.muni.ics.openid.connect.web.JWKSetPublishingEndpoint).URL}**" access="permitAll"/> <security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" /> <security:custom-filter ref="mdcFilter" before="FIRST"/> <security:csrf disabled="true"/> </security:http> - <security:http pattern="/#{T(org.mitre.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" use-expressions="true" entry-point-ref="http403EntryPoint" create-session="stateless"> - <security:intercept-url pattern="/#{T(org.mitre.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" access="permitAll"/> + <security:http pattern="/#{T(cz.muni.ics.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" use-expressions="true" entry-point-ref="http403EntryPoint" create-session="stateless"> + <security:intercept-url pattern="/#{T(cz.muni.ics.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" access="permitAll"/> <security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" /> <security:custom-filter ref="mdcFilter" before="FIRST"/> <security:csrf disabled="true"/> @@ -149,7 +149,7 @@ </security:http> <!-- OAuth-protect API and other endpoints --> - <security:http pattern="/#{T(org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless"> + <security:http pattern="/#{T(cz.muni.ics.openid.connect.web.DynamicClientRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless"> <security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" /> <security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" /> <security:custom-filter ref="mdcFilter" before="FIRST"/> @@ -158,7 +158,7 @@ <security:csrf disabled="true"/> </security:http> - <security:http pattern="/#{T(org.mitre.openid.connect.web.ProtectedResourceRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless"> + <security:http pattern="/#{T(cz.muni.ics.openid.connect.web.ProtectedResourceRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless"> <security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" /> <security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" /> <security:custom-filter ref="mdcFilter" before="FIRST"/> @@ -167,7 +167,7 @@ <security:csrf disabled="true"/> </security:http> - <security:http pattern="/#{T(org.mitre.openid.connect.web.UserInfoEndpoint).URL}**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless"> + <security:http pattern="/#{T(cz.muni.ics.openid.connect.web.UserInfoEndpoint).URL}**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless"> <security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" /> <security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" /> <security:custom-filter ref="mdcFilter" before="FIRST"/> @@ -175,14 +175,14 @@ <security:csrf disabled="true"/> </security:http> - <security:http pattern="/#{T(org.mitre.openid.connect.web.RootController).API_URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="never"> + <security:http pattern="/#{T(cz.muni.ics.openid.connect.web.RootController).API_URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="never"> <security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" /> <security:custom-filter ref="mdcFilter" before="FIRST"/> <security:expression-handler ref="oauthWebExpressionHandler" /> <security:csrf disabled="true"/> </security:http> - <security:http pattern="/#{T(org.mitre.oauth2.web.DeviceEndpoint).URL}/**" + <security:http pattern="/#{T(cz.muni.ics.oauth2.web.DeviceEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless" @@ -197,7 +197,7 @@ <security:csrf disabled="true"/> </security:http> - <security:http pattern="/#{T(org.mitre.oauth2.web.IntrospectionEndpoint).URL}**" + <security:http pattern="/#{T(cz.muni.ics.oauth2.web.IntrospectionEndpoint).URL}**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless" @@ -211,7 +211,7 @@ <security:csrf disabled="true"/> </security:http> - <security:http pattern="/#{T(org.mitre.oauth2.web.RevocationEndpoint).URL}**" + <security:http pattern="/#{T(cz.muni.ics.oauth2.web.RevocationEndpoint).URL}**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless" @@ -241,7 +241,7 @@ <bean id="oauth2ExceptionTranslator" class="org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator" /> - <bean id="clientAuthMatcher" class="org.mitre.openid.connect.filter.MultiUrlRequestMatcher"> + <bean id="clientAuthMatcher" class="cz.muni.ics.openid.connect.filter.MultiUrlRequestMatcher"> <constructor-arg name="filterProcessesUrls"> <set> <value>/introspect</value> @@ -256,7 +256,7 @@ <property name="requiresAuthenticationRequestMatcher" ref="clientAuthMatcher" /> </bean> - <bean id="clientAssertionEndpointFilter" class="org.mitre.openid.connect.assertion.JWTBearerClientAssertionTokenEndpointFilter"> + <bean id="clientAssertionEndpointFilter" class="cz.muni.ics.openid.connect.assertion.JWTBearerClientAssertionTokenEndpointFilter"> <constructor-arg name="additionalMatcher" ref="clientAuthMatcher" /> <property name="authenticationManager" ref="clientAssertionAuthenticationManager" /> </bean> @@ -270,7 +270,7 @@ <security:authentication-provider ref="clientAssertionAuthenticationProvider" /> </security:authentication-manager> - <bean id="clientAssertionAuthenticationProvider" class="org.mitre.openid.connect.assertion.JWTBearerAuthenticationProvider" /> + <bean id="clientAssertionAuthenticationProvider" class="cz.muni.ics.openid.connect.assertion.JWTBearerAuthenticationProvider" /> <!-- Configure locale information --> <import resource="locale-config.xml" /> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml similarity index 83% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml index 0ec4ce7f6..4836d3614 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml @@ -29,16 +29,16 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- validate incoming tokens for JWT assertions --> - <bean id="jwtAssertionValidator" class="org.mitre.jwt.assertion.impl.NullAssertionValidator" /> + <bean id="jwtAssertionValidator" class="cz.muni.ics.jwt.assertion.impl.NullAssertionValidator" /> <!-- translate incoming assertions to token authorization objects --> - <bean id="jwtAssertionTokenFactory" class="org.mitre.oauth2.assertion.impl.DirectCopyRequestFactory" /> + <bean id="jwtAssertionTokenFactory" class="cz.muni.ics.oauth2.assertion.impl.DirectCopyRequestFactory" /> <!-- validate client software statements for dynamic registration --> -<!-- <bean id="clientAssertionValidator" class="org.mitre.jwt.assertion.impl.NullAssertionValidator" /> --> +<!-- <bean id="clientAssertionValidator" class="cz.muni.ics.jwt.assertion.impl.NullAssertionValidator" /> --> <!-- this class will pass assertions signed by the issuers and keys in the whitelist --> - <bean id="clientAssertionValidator" class="org.mitre.jwt.assertion.impl.WhitelistedIssuerAssertionValidator"> + <bean id="clientAssertionValidator" class="cz.muni.ics.jwt.assertion.impl.WhitelistedIssuerAssertionValidator"> <property name="whitelist"> <map> <entry key="http://artemesia.local" value="http://localhost:8080/openid-connect-server-webapp/jwk" /> @@ -47,4 +47,4 @@ </bean> -</beans> \ No newline at end of file +</beans> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/authz-config.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/authz-config.xml similarity index 96% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/authz-config.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/authz-config.xml index 4d5242ae1..4ca0109b9 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/authz-config.xml +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/authz-config.xml @@ -52,7 +52,7 @@ <bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" /> - <bean id="oauthRequestValidator" class="org.mitre.oauth2.token.ScopeServiceAwareOAuth2RequestValidator" /> + <bean id="oauthRequestValidator" class="cz.muni.ics.oauth2.token.ScopeServiceAwareOAuth2RequestValidator" /> <!-- Error page handler. --> <mvc:view-controller path="/error" view-name="error" /> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/mysql/acrs.sql b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/mysql/acrs.sql new file mode 100644 index 000000000..0013f501a --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/mysql/acrs.sql @@ -0,0 +1,22 @@ +CREATE TABLE IF NOT EXISTS acrs ( + id BIGINT AUTO_INCREMENT, + client_id VARCHAR(2048) NOT NULL, + sub VARCHAR(2048) NOT NULL, + state VARCHAR(2048) NOT NULL, + shib_authn_context_class VARCHAR(2048) NOT NULL, + expiration BIGINT NOT NULL, + PRIMARY KEY (id) +); + +ALTER TABLE acrs MODIFY COLUMN expiration BIGINT; + +CREATE TABLE IF NOT EXISTS device_code_acrs ( + id BIGINT AUTO_INCREMENT, + device_code VARCHAR(2048) NOT NULL, + user_code VARCHAR(2048) NOT NULL, + shib_authn_context_class VARCHAR(2048), + expiration BIGINT NOT NULL, + PRIMARY KEY (id) +); + +ALTER TABLE device_code_acrs MODIFY COLUMN expiration BIGINT; diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/mysql/db_update.sql b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/mysql/db_update.sql new file mode 100644 index 000000000..733cc6e7d --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/mysql/db_update.sql @@ -0,0 +1,10 @@ +ALTER TABLE authentication_holder_request_parameter +MODIFY COLUMN val TEXT; + +CREATE TABLE shedlock( + name VARCHAR(64), + lock_until TIMESTAMP(3) NULL, + locked_at TIMESTAMP(3) NULL, + locked_by VARCHAR(255), + PRIMARY KEY (name) +); diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/mysql/scopes.sql b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/mysql/scopes.sql new file mode 100644 index 000000000..15bb8f1ef --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/mysql/scopes.sql @@ -0,0 +1,39 @@ +-- +-- Turn off autocommit and start a transaction so that we can use the temp tables +-- + +SET AUTOCOMMIT = 0; + +START TRANSACTION; + +CREATE TEMPORARY TABLE IF NOT EXISTS system_scope_TEMP ( + scope VARCHAR(256), + description VARCHAR(4096), + icon VARCHAR(256), + restricted BOOLEAN, + default_scope BOOLEAN +); +-- +-- Insert scope information into the temporary tables. +-- + +INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope) VALUES + ('openid', 'log in using your identity', 'user', false, true), + ('profile', 'basic profile information', 'list-alt', false, true), + ('email', 'email address', 'envelope', false, true), + ('address', 'physical address', 'home', false, true), + ('phone', 'telephone number', 'bell', false, true), + ('offline_access', 'offline access', 'time', false, false), + ('perun_api', 'calls to Perun API in your roles', 'cog', true, false); + +-- +-- Merge the temporary scopes safely into the database. This is a two-step process to keep scopes from being created on every startup with a persistent store. +-- + +INSERT INTO system_scope (scope, description, icon, restricted, default_scope) + SELECT scope, description, icon, restricted, default_scope FROM system_scope_TEMP + ON DUPLICATE KEY UPDATE system_scope.scope = system_scope.scope; + +COMMIT; + +SET AUTOCOMMIT = 1; diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/acrs.sql b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/acrs.sql new file mode 100644 index 000000000..96f415140 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/acrs.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS acrs ( + id BIGINT AUTO_INCREMENT, + client_id VARCHAR(2048) NOT NULL, + sub VARCHAR(2048) NOT NULL, + acr_values VARCHAR(2048) NOT NULL, + state VARCHAR(2048) NOT NULL, + shib_authn_context_class VARCHAR(2048) NOT NULL, + expiration BIGINT NOT NULL, + PRIMARY KEY (id) +); + +ALTER TABLE acrs MODIFY COLUMN expiration BIGINT; diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/db_update.sql b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/db_update.sql new file mode 100644 index 000000000..5eca832d6 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/db_update.sql @@ -0,0 +1,7 @@ +CREATE TABLE shedlock( + name VARCHAR(64), + lock_until TIMESTAMP(3) NULL, + locked_at TIMESTAMP(3) NULL, + locked_by VARCHAR(255), + PRIMARY KEY (name) +); diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/loading_temp_tables.sql b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/loading_temp_tables.sql new file mode 100644 index 000000000..37b0092e7 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/loading_temp_tables.sql @@ -0,0 +1,73 @@ +-- +-- Temporary tables used during the bootstrapping process to safely load users and clients. +-- These are not needed if you're not using the users.sql/clients.sql files to bootstrap the database. +-- + +CREATE TEMPORARY TABLE IF NOT EXISTS authorities_TEMP ( + username varchar(50) not null, + authority varchar(50) not null, + constraint ix_authority_TEMP unique (username,authority)); + +CREATE TEMPORARY TABLE IF NOT EXISTS users_TEMP ( + username varchar(50) not null primary key, + password varchar(50) not null, + enabled boolean not null); + +CREATE TEMPORARY TABLE IF NOT EXISTS user_info_TEMP ( + sub VARCHAR(256) not null primary key, + preferred_username VARCHAR(256), + name VARCHAR(256), + given_name VARCHAR(256), + family_name VARCHAR(256), + middle_name VARCHAR(256), + nickname VARCHAR(256), + profile VARCHAR(256), + picture VARCHAR(256), + website VARCHAR(256), + email VARCHAR(256), + email_verified BOOLEAN, + gender VARCHAR(256), + zone_info VARCHAR(256), + locale VARCHAR(256), + phone_number VARCHAR(256), + address_id VARCHAR(256), + updated_time VARCHAR(256), + birthdate VARCHAR(256) +); + +CREATE TEMPORARY TABLE IF NOT EXISTS client_details_TEMP ( + client_description VARCHAR(256), + dynamically_registered BOOLEAN, + id_token_validity_seconds BIGINT, + + client_id VARCHAR(256), + client_secret VARCHAR(2048), + access_token_validity_seconds BIGINT, + refresh_token_validity_seconds BIGINT, + allow_introspection BOOLEAN, + + client_name VARCHAR(256) +); + +CREATE TEMPORARY TABLE IF NOT EXISTS client_scope_TEMP ( + owner_id VARCHAR(256), + scope VARCHAR(2048) +); + +CREATE TEMPORARY TABLE IF NOT EXISTS client_redirect_uri_TEMP ( + owner_id VARCHAR(256), + redirect_uri VARCHAR(2048) +); + +CREATE TEMPORARY TABLE IF NOT EXISTS client_grant_type_TEMP ( + owner_id VARCHAR(256), + grant_type VARCHAR(2000) +); + +CREATE TEMPORARY TABLE IF NOT EXISTS system_scope_TEMP ( + scope VARCHAR(256), + description VARCHAR(4096), + icon VARCHAR(256), + restricted BOOLEAN, + default_scope BOOLEAN +); \ No newline at end of file diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/psql_database_tables.sql b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/psql_database_tables.sql new file mode 100644 index 000000000..9a5c867d5 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/psql_database_tables.sql @@ -0,0 +1,384 @@ +-- +-- Tables for OIDC Server functionality, PostgreSQL +-- + +CREATE TABLE IF NOT EXISTS access_token ( + id SERIAL PRIMARY KEY, + token_value VARCHAR(4096), + expiration TIMESTAMP, + token_type VARCHAR(256), + refresh_token_id BIGINT, + client_id BIGINT, + auth_holder_id BIGINT, + approved_site_id BIGINT, + UNIQUE(token_value) +); + +CREATE TABLE IF NOT EXISTS access_token_permissions ( + access_token_id BIGINT NOT NULL, + permission_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS address ( + id SERIAL PRIMARY KEY, + formatted VARCHAR(256), + street_address VARCHAR(256), + locality VARCHAR(256), + region VARCHAR(256), + postal_code VARCHAR(256), + country VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS approved_site ( + id SERIAL PRIMARY KEY, + user_id VARCHAR(256), + client_id VARCHAR(256), + creation_date TIMESTAMP, + access_date TIMESTAMP, + timeout_date TIMESTAMP, + whitelisted_site_id BIGINT +); + +CREATE TABLE IF NOT EXISTS approved_site_scope ( + owner_id BIGINT, + scope VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder ( + id SERIAL PRIMARY KEY, + user_auth_id BIGINT, + approved BOOLEAN, + redirect_uri VARCHAR(2048), + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_resource_id ( + owner_id BIGINT, + resource_id VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_response_type ( + owner_id BIGINT, + response_type VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_extension ( + owner_id BIGINT, + extension VARCHAR(2048), + val VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_request_parameter ( + owner_id BIGINT, + param VARCHAR(2048), + val TEXT +); + +CREATE TABLE IF NOT EXISTS saved_user_auth ( + id SERIAL PRIMARY KEY, + name VARCHAR(1024), + authenticated BOOLEAN, + source_class VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS saved_user_auth_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authorization_code ( + id SERIAL PRIMARY KEY, + code VARCHAR(256), + auth_holder_id BIGINT, + expiration TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS client_grant_type ( + owner_id BIGINT, + grant_type VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_response_type ( + owner_id BIGINT, + response_type VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS blacklisted_site ( + id SERIAL PRIMARY KEY, + uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS client_details ( + id SERIAL PRIMARY KEY, + + client_description VARCHAR(1024), + reuse_refresh_tokens BOOLEAN DEFAULT true NOT NULL, + dynamically_registered BOOLEAN DEFAULT false NOT NULL, + allow_introspection BOOLEAN DEFAULT false NOT NULL, + id_token_validity_seconds BIGINT DEFAULT 600 NOT NULL, + device_code_validity_seconds BIGINT, + + client_id VARCHAR(256), + client_secret VARCHAR(2048), + access_token_validity_seconds BIGINT, + refresh_token_validity_seconds BIGINT, + + application_type VARCHAR(256), + client_name VARCHAR(256), + token_endpoint_auth_method VARCHAR(256), + subject_type VARCHAR(256), + + logo_uri VARCHAR(2048), + policy_uri VARCHAR(2048), + client_uri VARCHAR(2048), + tos_uri VARCHAR(2048), + + jwks_uri VARCHAR(2048), + jwks VARCHAR(8192), + sector_identifier_uri VARCHAR(2048), + + request_object_signing_alg VARCHAR(256), + + user_info_signed_response_alg VARCHAR(256), + user_info_encrypted_response_alg VARCHAR(256), + user_info_encrypted_response_enc VARCHAR(256), + + id_token_signed_response_alg VARCHAR(256), + id_token_encrypted_response_alg VARCHAR(256), + id_token_encrypted_response_enc VARCHAR(256), + + token_endpoint_auth_signing_alg VARCHAR(256), + + default_max_age BIGINT, + require_auth_time BOOLEAN, + created_at TIMESTAMP, + initiate_login_uri VARCHAR(2048), + clear_access_tokens_on_refresh BOOLEAN DEFAULT true NOT NULL, + + software_statement VARCHAR(4096), + software_id VARCHAR(2048), + software_version VARCHAR(2048), + + code_challenge_method VARCHAR(256), + + UNIQUE (client_id) +); + +CREATE TABLE IF NOT EXISTS client_request_uri ( + owner_id BIGINT, + request_uri VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_post_logout_redirect_uri ( + owner_id BIGINT, + post_logout_redirect_uri VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_default_acr_value ( + owner_id BIGINT, + default_acr_value VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_contact ( + owner_id BIGINT, + contact VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_redirect_uri ( + owner_id BIGINT, + redirect_uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS client_claims_redirect_uri ( + owner_id BIGINT, + redirect_uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS refresh_token ( + id SERIAL PRIMARY KEY, + token_value VARCHAR(4096), + expiration TIMESTAMP, + auth_holder_id BIGINT, + client_id BIGINT +); + +CREATE TABLE IF NOT EXISTS client_resource ( + owner_id BIGINT, + resource_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS token_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS system_scope ( + id SERIAL PRIMARY KEY, + scope VARCHAR(256) NOT NULL, + description VARCHAR(4096), + icon VARCHAR(256), + restricted BOOLEAN DEFAULT false NOT NULL, + default_scope BOOLEAN DEFAULT false NOT NULL, + UNIQUE (scope) +); + +CREATE TABLE IF NOT EXISTS user_info ( + id SERIAL PRIMARY KEY, + sub VARCHAR(256), + preferred_username VARCHAR(256), + name VARCHAR(256), + given_name VARCHAR(256), + family_name VARCHAR(256), + middle_name VARCHAR(256), + nickname VARCHAR(256), + profile VARCHAR(256), + picture VARCHAR(256), + website VARCHAR(256), + email VARCHAR(256), + email_verified BOOLEAN, + gender VARCHAR(256), + zone_info VARCHAR(256), + locale VARCHAR(256), + phone_number VARCHAR(256), + phone_number_verified BOOLEAN, + address_id VARCHAR(256), + updated_time VARCHAR(256), + birthdate VARCHAR(256), + src VARCHAR(4096) +); + +CREATE TABLE IF NOT EXISTS whitelisted_site ( + id SERIAL PRIMARY KEY, + creator_user_id VARCHAR(256), + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS whitelisted_site_scope ( + owner_id BIGINT, + scope VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS pairwise_identifier ( + id SERIAL PRIMARY KEY, + identifier VARCHAR(256), + sub VARCHAR(256), + sector_identifier VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS resource_set ( + id SERIAL PRIMARY KEY, + name VARCHAR(1024) NOT NULL, + uri VARCHAR(1024), + icon_uri VARCHAR(1024), + rs_type VARCHAR(256), + owner VARCHAR(256) NOT NULL, + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS resource_set_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS permission_ticket ( + id SERIAL PRIMARY KEY, + ticket VARCHAR(256) NOT NULL, + permission_id BIGINT NOT NULL, + expiration TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS permission ( + id SERIAL PRIMARY KEY, + resource_set_id BIGINT +); + +CREATE TABLE IF NOT EXISTS permission_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim ( + id SERIAL PRIMARY KEY, + name VARCHAR(256), + friendly_name VARCHAR(1024), + claim_type VARCHAR(1024), + claim_value VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS claim_to_policy ( + policy_id BIGINT NOT NULL, + claim_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim_to_permission_ticket ( + permission_ticket_id BIGINT NOT NULL, + claim_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS policy ( + id SERIAL PRIMARY KEY, + name VARCHAR(1024), + resource_set_id BIGINT +); + +CREATE TABLE IF NOT EXISTS policy_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim_token_format ( + owner_id BIGINT NOT NULL, + claim_token_format VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS claim_issuer ( + owner_id BIGINT NOT NULL, + issuer VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS saved_registered_client ( + id SERIAL PRIMARY KEY, + issuer VARCHAR(1024), + registered_client VARCHAR(8192) +); + +CREATE TABLE IF NOT EXISTS device_code ( + id BIGSERIAL PRIMARY KEY, + device_code VARCHAR(1024), + user_code VARCHAR(1024), + expiration TIMESTAMP NULL, + client_id VARCHAR(256), + approved BOOLEAN, + auth_holder_id BIGINT +); + +CREATE TABLE IF NOT EXISTS device_code_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS device_code_request_parameter ( + owner_id BIGINT, + param VARCHAR(2048), + val VARCHAR(2048) +); diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/scopes.sql b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/scopes.sql new file mode 100644 index 000000000..e316b04db --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/classes/db/psql/scopes.sql @@ -0,0 +1,35 @@ +-- +-- Turn off autocommit and start a transaction so that we can use the temp tables +-- + +--SET AUTOCOMMIT = OFF; + +START TRANSACTION; + +-- +-- Insert scope information into the temporary tables. +-- + +INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope) VALUES + ('openid', 'log in using your identity', 'user', false, true), + ('profile', 'basic profile information', 'list-alt', false, true), + ('email', 'email address', 'envelope', false, true), + ('address', 'physical address', 'home', false, true), + ('phone', 'telephone number', 'bell', false, true), + ('offline_access', 'offline access', 'time', false, false), + ('perun_api', 'calls to Perun API in your roles', 'cog', true, false) + ; + +-- +-- Merge the temporary scopes safely into the database. This is a two-step process to keep scopes from being created on every startup with a persistent store. +-- + +INSERT INTO system_scope (scope, description, icon, restricted, default_scope) + SELECT scope, description, icon, restricted, default_scope FROM system_scope_TEMP + ON CONFLICT(scope) + DO NOTHING; + +COMMIT; + +--SET AUTOCOMMIT = ON; + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/crypto-config.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/crypto-config.xml similarity index 88% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/crypto-config.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/crypto-config.xml index c1e47a8dc..933b5c333 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/crypto-config.xml +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/crypto-config.xml @@ -30,17 +30,17 @@ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> - <bean id="defaultKeyStore" class="org.mitre.jose.keystore.JWKSetKeyStore"> + <bean id="defaultKeyStore" class="cz.muni.ics.jose.keystore.JWKSetKeyStore"> <property name="location" value="classpath:keystore.jwks" /> </bean> - <bean id="defaultsignerService" class="org.mitre.jwt.signer.service.impl.DefaultJWTSigningAndValidationService"> + <bean id="defaultsignerService" class="cz.muni.ics.jwt.signer.service.impl.DefaultJWTSigningAndValidationService"> <constructor-arg name="keyStore" ref="defaultKeyStore" /> <property name="defaultSignerKeyId" value="rsa1" /> <property name="defaultSigningAlgorithmName" value="RS256" /> </bean> - <bean id="defaultEncryptionService" class="org.mitre.jwt.encryption.service.impl.DefaultJWTEncryptionAndDecryptionService"> + <bean id="defaultEncryptionService" class="cz.muni.ics.jwt.encryption.service.impl.DefaultJWTEncryptionAndDecryptionService"> <constructor-arg name="keyStore" ref="defaultKeyStore" /> <property name="defaultAlgorithm" value="RSA1_5" /> <property name="defaultDecryptionKeyId" value="rsa1" /> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/data-context.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/data-context.xml new file mode 100644 index 000000000..b484eb6c9 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/data-context.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2018 The MIT Internet Trust Consortium + + Portions copyright 2011-2013 The MITRE Corporation + + 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. + --> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:jdbc="http://www.springframework.org/schema/jdbc" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd + http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd"> + + <!-- The following is for connecting to a PostgreSQL database that has been initialized with + src/main/resources/db/psql/psql_database_tables.sql --> + <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"> + <property name="driverClassName" value="${jdbc.driver}" /> + <property name="jdbcUrl" value="${jdbc.url}" /> + <property name="username" value="${jdbc.user}" /> + <property name="password" value="${jdbc.password}" /> + <property name="maximumPoolSize" value="50" /> + </bean> + + <bean id="mitreIdStats" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"> + <property name="driverClassName" value="${jdbc.driver}" /> + <property name="jdbcUrl" value="${stats.jdbc.url}" /> + <property name="username" value="${stats.jdbc.user}" /> + <property name="password" value="${stats.jdbc.password}" /> + </bean> + + <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> + <property name="databasePlatform" value="${jdbc.platform}" /> + <property name="showSql" value="false" /> + </bean> + <!-- Initialize the database + <jdbc:initialize-database data-source="dataSource"> + <jdbc:script location="classpath:/db/mysql/mysql_database_tables.sql"/> + <jdbc:script location="classpath:/db/mysql/scopes.sql"/> + </jdbc:initialize-database> + --> + +</beans> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/endpoint-config.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/endpoint-config.xml similarity index 69% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/endpoint-config.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/endpoint-config.xml index 14fbcf2ea..44390d5de 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/endpoint-config.xml +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/endpoint-config.xml @@ -29,6 +29,18 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> -<!-- This file allows you to define additional endpoints, it's normally empty in the OIDC server and has entries in the UMA server --> + <security:http pattern="/devicecodeMFA/**" + use-expressions="true" + entry-point-ref="oauthAuthenticationEntryPoint" + create-session="stateless" + authentication-manager-ref="clientAuthenticationManager"> + <security:http-basic entry-point-ref="oauthAuthenticationEntryPoint" /> + <!-- include this only if you need to authenticate clients via request parameters --> + <security:custom-filter ref="clientAssertionEndpointFilter" after="PRE_AUTH_FILTER" /> <!-- this one has to go first --> + <security:custom-filter ref="clientCredentialsEndpointFilter" after="BASIC_AUTH_FILTER" /> + <security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" /> + <security:access-denied-handler ref="oauthAccessDeniedHandler" /> + <security:csrf disabled="true"/> + </security:http> </beans> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/jpa-config.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/jpa-config.xml similarity index 98% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/jpa-config.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/jpa-config.xml index 592d56a2e..4cbd44c60 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/jpa-config.xml +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/jpa-config.xml @@ -34,7 +34,7 @@ </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> - <property name="packagesToScan" value="org.mitre" /> + <property name="packagesToScan" value="cz.muni.ics" /> <property name="persistenceProviderClass" value="org.eclipse.persistence.jpa.PersistenceProvider" /> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter" ref="jpaAdapter" /> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/local-config.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/local-config.xml similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/local-config.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/local-config.xml diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/locale-config.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/locale-config.xml similarity index 84% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/locale-config.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/locale-config.xml index 60cdb6b0f..7f6e95dc7 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/locale-config.xml +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/locale-config.xml @@ -19,11 +19,11 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - <bean id="messageSource" class="org.mitre.openid.connect.config.JsonMessageSource"> + <bean id="messageSource" class="cz.muni.ics.openid.connect.config.JsonMessageSource"> <property name="baseDirectory" value="/resources/js/locale/" /> <property name="useCodeAsDefaultMessage" value="true" /> </bean> - <bean id="localeResolver" class="org.mitre.openid.connect.config.ConfigurationBeanLocaleResolver" /> + <bean id="localeResolver" class="cz.muni.ics.openid.connect.config.ConfigurationBeanLocaleResolver" /> </beans> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/user-context.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/server-config.xml similarity index 63% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/user-context.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/server-config.xml index 86e4be23c..e28024d45 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/user-context.xml +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/server-config.xml @@ -30,29 +30,18 @@ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> - <security:authentication-manager id="authenticationManager"> - <security:authentication-provider> - <security:jdbc-user-service data-source-ref="dataSource"/> - </security:authentication-provider> - </security:authentication-manager> - - <mvc:view-controller path="/login" view-name="login" /> - - <security:http authentication-manager-ref="authenticationManager"> + <bean id="configBean" class="cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean"> + <!-- This property sets the root URL of the server, known as the issuer --> + <property name="issuer" value="${main.oidc.issuer.url}" /> + <!-- This property is a URL pointing to a logo image 24px high to be used in the top bar --> + <property name="logoImageUrl" value="${logo.image.url}" /> + <!-- This property sets the display name of the server, displayed in the topbar and page title --> + <property name="topbarTitle" value="${topbar.title}" /> + <!-- This property forces the issuer value to start with "https", recommended on production servers --> + <property name="forceHttps" value="true" /> + <!-- This property allows the server to create and accept fully-composed + user URIs (with the user-code emebedded) for the device flow --> + <property name="allowCompleteDeviceCodeUri" value="true" /> + </bean> - <security:intercept-url pattern="/authorize" access="hasRole('ROLE_USER')" /> - <security:intercept-url pattern="/**" access="permitAll" /> - - <security:form-login login-page="/login" authentication-failure-url="/login?error=failure" authentication-success-handler-ref="authenticationTimeStamper" /> - <security:custom-filter ref="authRequestFilter" after="SECURITY_CONTEXT_FILTER" /> - <security:logout logout-url="/logout" /> - <security:anonymous /> - <security:expression-handler ref="oauthWebExpressionHandler" /> - <security:headers> - <security:frame-options policy="DENY" /> - </security:headers> - <security:csrf /> - <security:custom-filter ref="mdcFilter" before="FIRST"/> - </security:http> - </beans> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/spring-servlet.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/spring-servlet.xml similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/spring-servlet.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/spring-servlet.xml diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/actionmenu.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/actionmenu.tag similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/actionmenu.tag rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/actionmenu.tag diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/bbmri/footer.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/bbmri/footer.tag new file mode 100644 index 000000000..e6d160f0b --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/bbmri/footer.tag @@ -0,0 +1,25 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ attribute name="js" required="false"%> +<%@ attribute name="baseURL" required="true"%> +<%@ attribute name="samlResourcesURL" required="true"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> +<jsp:useBean id="date" class="java.util.Date" /> + +<div id="footer"> + <div style="margin: 0px auto; max-width: 1000px;"> + <div style="float: left;"> + <img src="${samlResourcesURL}/module.php/bbmri/res/img/BBMRI-ERIC-gateway-for-health_216.png" alt="BBMRI-ERIC Logo"> + </div> + + <div style="float: left;"> + <p>BBMRI-ERIC, Neue Stiftingtalstrasse 2/B/6, 8010 Graz, Austria + +43 316 34 99 17-0 + <a href="mailto:contact@bbmri-eric.eu">contact@bbmri-eric.eu</a> + </p> + <p>Copyright © BBMRI-ERIC <fmt:formatDate value="${date}" pattern="yyyy" /></p> + </div> + </div> +</div><!-- #footer --> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/bbmri/header.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/bbmri/header.tag new file mode 100644 index 000000000..aeb0a8b7e --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/bbmri/header.tag @@ -0,0 +1,22 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags/common" %> +<%@ attribute name="title" required="true" %> +<%@ attribute name="reqURL" required="true" %> +<%@ attribute name="baseURL" required="true" %> +<%@ attribute name="samlResourcesURL" required="true" %> +<%@ attribute name="cssLinks" required="true" type="java.util.ArrayList<java.lang.String>" %> + +<c:set var="logoURL" value="${samlResourcesURL}/module.php/bbmri/res/img/BBMRI-ERIC-gateway-for-health_430.png"/> + +<o:headerInit title="${title}" reqURL="${reqURL}" baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}" /> + +<link rel="stylesheet" type="text/css" href="${samlResourcesURL}/module.php/bbmri/res/bootstrap/css/bootstrap.min.css" /> +<link rel="stylesheet" type="text/css" href="${samlResourcesURL}/module.php/bbmri/res/css/bbmri.css" /> + +<o:headerCssLinks cssLinks="${cssLinks}"/> + +</head> + +<o:headerBody logoURL="${logoURL}"/> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/ceitec/footer.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/ceitec/footer.tag new file mode 100644 index 000000000..124fc6fb0 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/ceitec/footer.tag @@ -0,0 +1,26 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ attribute name="js" required="false"%> +<%@ attribute name="baseURL" required="true"%> +<%@ attribute name="samlResourcesURL" required="true"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> +<jsp:useBean id="date" class="java.util.Date" /> + +<c:set var="issuer" value="${config.issuer}" /> + +<div id="footer"> + <div style="margin: 0px auto; max-width: 1000px;"> + <div style="float: left;"> + <img src="${samlResourcesURL}/module.php/ceitec/res/img/logo_64.png" alt="CEITEC Logo"> + </div> + <div style="float: left;"> + <p>CEITEC, Masaryk University, Žerotínovo nám. 9, 601 77 Brno, Czech Republic + +420 549 498 732 + <a href="mailto:is.ceitec@ceitec.cz">is.ceitec@ceitec.cz</a> + </p> + <p>Copyright © CEITEC <fmt:formatDate value="${date}" pattern="yyyy" /></p> + </div> + </div> +</div> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/ceitec/header.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/ceitec/header.tag new file mode 100644 index 000000000..4214110df --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/ceitec/header.tag @@ -0,0 +1,22 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags/common" %> +<%@ attribute name="title" required="true" %> +<%@ attribute name="reqURL" required="true" %> +<%@ attribute name="baseURL" required="true" %> +<%@ attribute name="samlResourcesURL" required="true" %> +<%@ attribute name="cssLinks" required="true" type="java.util.ArrayList<java.lang.String>" %> + +<c:set var="logoURL" value="${samlResourcesURL}/module.php/ceitec/res/img/logo_512.png"/> + +<o:headerInit title="${title}" reqURL="${reqURL}" baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + +<link rel="stylesheet" type="text/css" href="${samlResourcesURL}/module.php/ceitec/res/bootstrap/css/bootstrap.min.css" /> +<link rel="stylesheet" type="text/css" href="${samlResourcesURL}/module.php/ceitec/res/css/ceitec.css" /> + +<o:headerCssLinks cssLinks="${cssLinks}"/> + +</head> + +<o:headerBody logoURL="${logoURL}"/> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/cesnet/footer.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/cesnet/footer.tag new file mode 100644 index 000000000..e84472bb5 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/cesnet/footer.tag @@ -0,0 +1,50 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ attribute name="js" required="false"%> +<%@ attribute name="baseURL" required="true"%> +<%@ attribute name="samlResourcesURL" required="true"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> +<jsp:useBean id="date" class="java.util.Date" /> + +<div id="footer"> + <footer> + <div class="container"> + <div class="row"> + <div class="col-md-4 logo"> + <a href="http://www.cesnet.cz/"> + <img src="${samlResourcesURL}/module.php/cesnet/res/img/logo-cesnet.png" alt="CESNET logo" style="width: 250px;"> + </a> + </div> + <div class="col-md-8"> + <div class="row"> + <div class="col col-sm-6"> + <h2>${langProps['footer_other_projects']}</h2> + <ul> + <li><a href="http://www.cesnet.cz/wp-content/uploads/2014/04/CzechLight-family_Posp%C3%ADchal.pdf">CzechLight</a></li> + <li><a href="http://www.ultragrid.cz/en">UltraGrid</a></li> + <li><a href="http://www.4kgateway.com/">4k Gateway</a></li> + <li><a href="http://shongo.cesnet.cz/">Shongo</a></li> + <li><a href="http://www.cesnet.cz/sluzby/sledovani-provozu-site/sledovani-infrastruktury/">FTAS a G3</a></li> + <li><a href="https://www.liberouter.org/">Librerouter</a></li> + </ul> + </div> + <div class="col col-sm-6"> + <h2>${langProps['footer_helpdesk']}</h2> + TEL: +420 224 352 994<br> + GSM: +420 602 252 531<br> + FAX: +420 224 313 211<br> + <a href="mailto:perun@cesnet.cz">perun@cesnet.cz</a> + </div> + </div> + </div> + </div> + <div class="row"> + <div class="col col-sm-12 copyright"> + © 1991–<fmt:formatDate value="${date}" pattern="yyyy" /> | CESNET, z. s. p. o. + </div> + </div> + </div> + </footer> +</div> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/cesnet/header.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/cesnet/header.tag new file mode 100644 index 000000000..e25dce99c --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/cesnet/header.tag @@ -0,0 +1,22 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags/common" %> +<%@ attribute name="title" required="true" %> +<%@ attribute name="reqURL" required="true" %> +<%@ attribute name="baseURL" required="true" %> +<%@ attribute name="samlResourcesURL" required="true" %> +<%@ attribute name="cssLinks" required="true" type="java.util.ArrayList<java.lang.String>" %> + +<c:set var="logoURL" value="${samlResourcesURL}/module.php/cesnet/res/img/cesnet_RGB.png"/> + +<o:headerInit title="${title}" reqURL="${reqURL}" baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}" /> + +<link rel="stylesheet" type="text/css" href="${samlResourcesURL}/module.php/cesnet/res/bootstrap/css/bootstrap.min.css" /> +<link rel="stylesheet" type="text/css" href="${samlResourcesURL}/module.php/cesnet/res/css/cesnet.css" /> + +<o:headerCssLinks cssLinks="${cssLinks}"/> + +</head> + +<o:headerBody logoURL="${logoURL}"/> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/attributesConsent.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/attributesConsent.tag new file mode 100644 index 000000000..150501da8 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/attributesConsent.tag @@ -0,0 +1,82 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" + import="cz.muni.ics.oidc.server.elixir.GA4GHClaimSource" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags" %> + +<c:if test="${empty scopes}"> + <p>${langProps['no_scopes']}</p> +</c:if> +<c:if test="${not empty scopes}"> + <ul id="perun-table_with_attributes" class="perun-attributes"> + <c:forEach var="scope" items="${scopes}"> + <c:set var="scopeValue" value="${langProps[scope.value]}"/> + <c:if test="${empty fn:trim(scopeValue)}"> + <c:set var="scopeValue" value="${scope.value}"/> + </c:if> + <c:set var="singleClaim" value="${fn:length(claims[scope.value]) eq 1}" /> + <li class="scope-item scope_${fn:escapeXml(scope.value)} ${' '} ${fn:length(claims[scope.value]) eq 0 ? 'hidden' : ''}"> + <div class="row"> + <div class="col-sm-5"> + <div class="checkbox-wrapper"> + <input class="mt-0 mr-half" type="checkbox" name="scope_${ fn:escapeXml(scope.value) }" checked="checked" + id="scope_${fn:escapeXml(scope.value)}" value="${fn:escapeXml(scope.value)}"> + </div> + <h2 class="perun-attrname <c:out value="${classes['perun-attrname.h2.class']}"/>"> + <label for="scope_${fn:escapeXml(scope.value)}" + class="<c:out value="${classes['perun-attrname.h2.class']}"/>">${scopeValue}</label> + </h2> + </div> + <div class="perun-attrcontainer col-sm-7"> + <span class="perun-attrvalue"> + <ul class="perun-attrlist <c:out value="${classes['perun-attrcontainer.ul.class']}"/>"> + <c:forEach var="claim" items="${claims[scope.value]}"> + <c:choose> + <c:when test="${not singleClaim}"> + <li class="subclaim subclaim_${fn:escapeXml(claim.key)}"> + <c:set var="claimKey" value="${langProps[claim.key]}"/> + <c:if test="${empty fn:trim(claimKey)}"> + <c:set var="claimKey" value="${claim.key}"/> + </c:if> + <h3 class="visible-xs-block visible-sm-inline-block visible-md-inline-block + visible-lg-inline-block <c:out value="${classes['perun-attrlist.h3.class']}"/>"> + ${claimKey}: + </h3> + <c:if test="${claim.value.getClass().name eq 'java.util.ArrayList'}"> + <ul class="subclaim-value">visible-md-inline-block + <c:forEach var="subValue" items="${claim.value}"> + <li>${subValue}</li> + </c:forEach> + </ul> + </c:if> + <c:if test="${not(claim.value.getClass().name eq 'java.util.ArrayList')}"> + <span class="subclaim-value">${claim.value}</span> + </c:if> + </li> + </c:when> + <c:when test="${claim.value.getClass().name eq 'java.util.ArrayList'}"> + <c:forEach var="subValue" items="${claim.value}"> + <c:choose> + <c:when test="${claim.key=='ga4gh_passport_v1'}"> + <li><%= GA4GHClaimSource.parseAndVerifyVisa( + (String) jspContext.findAttribute("subValue")).getPrettyString() %></li> + </c:when> + <c:otherwise> + <li>${subValue}</li> + </c:otherwise> + </c:choose> + </c:forEach> + </c:when> + <c:otherwise> + <li>${claim.value}</li> + </c:otherwise> + </c:choose> + </c:forEach> + </ul> + </span> + </div> + </div> + </li> + </c:forEach> + </ul> +</c:if> \ No newline at end of file diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/consentButtons.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/consentButtons.tag new file mode 100644 index 000000000..9b65cc499 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/consentButtons.tag @@ -0,0 +1,22 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags" %> + +<div class="row"> + <div class="col-sm-6"> + <div id="yesform"> + <button id="yesbutton" name="yes" type="submit" class="btn btn-success btn-lg btn-block btn-primary" + onclick="$('#user_oauth_approval').attr('value', true);"> + <span>${langProps['yes']}</span> + </button> + </div> + </div> + <div class="col-sm-6"> + <div> + <button id="nobutton" name="no" type="submit" class="btn btn-lg btn-default btn-block btn-no" + onclick="$('#user_oauth_approval').attr('value', false);"> + <span>${langProps['no']}</span> + </button> + </div> + </div> +</div> \ No newline at end of file diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/footer.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/footer.tag new file mode 100644 index 000000000..7a9a97f96 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/footer.tag @@ -0,0 +1,38 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="elixir" tagdir="/WEB-INF/tags/elixir" %> +<%@ taglib prefix="cesnet" tagdir="/WEB-INF/tags/cesnet" %> +<%@ taglib prefix="bbmri" tagdir="/WEB-INF/tags/bbmri" %> +<%@ taglib prefix="ceitec" tagdir="/WEB-INF/tags/ceitec" %> +<%@ taglib prefix="europdx" tagdir="/WEB-INF/tags/europdx" %> +<%@ taglib prefix="muni" tagdir="/WEB-INF/tags/muni" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> +<%@ attribute name="baseURL" required="true" %> +<%@ attribute name="theme" required="true" %> + +<c:choose> + <c:when test="${theme eq 'elixir'}"> + <elixir:footer baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + </c:when> + <c:when test="${theme eq 'cesnet'}"> + <cesnet:footer baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + </c:when> + <c:when test="${theme eq 'bbmri'}"> + <bbmri:footer baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + </c:when> + <c:when test="${theme eq 'ceitec'}"> + <ceitec:footer baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + </c:when> + <c:when test="${theme eq 'europdx'}"> + <europdx:footer baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + </c:when> + <c:when test="${theme eq 'muni'}"> + <muni:footer/> + </c:when> + <c:otherwise> + <o:footer /> + </c:otherwise> +</c:choose> + +<script type="text/javascript" src="resources/js/jquery-3-3-1.min.js"></script> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/header.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/header.tag new file mode 100644 index 000000000..7814e0936 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/header.tag @@ -0,0 +1,38 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="elixir" tagdir="/WEB-INF/tags/elixir" %> +<%@ taglib prefix="cesnet" tagdir="/WEB-INF/tags/cesnet" %> +<%@ taglib prefix="bbmri" tagdir="/WEB-INF/tags/bbmri" %> +<%@ taglib prefix="ceitec" tagdir="/WEB-INF/tags/ceitec" %> +<%@ taglib prefix="europdx" tagdir="/WEB-INF/tags/europdx" %> +<%@ taglib prefix="muni" tagdir="/WEB-INF/tags/muni" %> +<%@ attribute name="title" required="true" %> +<%@ attribute name="reqURL" required="true" %> +<%@ attribute name="baseURL" required="true" %> +<%@ attribute name="theme" required="true" %> +<%@ attribute name="cssLinks" required="true" type="java.util.ArrayList<java.lang.String>" %> + +<c:choose> + <c:when test="${theme eq 'elixir'}"> + <elixir:header title="${title}" reqURL="${reqURL}" cssLinks="${cssLinks}" baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + </c:when> + <c:when test="${theme eq 'cesnet'}"> + <cesnet:header title="${title}" reqURL="${reqURL}" cssLinks="${cssLinks}" baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + </c:when> + <c:when test="${theme eq 'bbmri'}"> + <bbmri:header title="${title}" reqURL="${reqURL}" cssLinks="${cssLinks}" baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + </c:when> + <c:when test="${theme eq 'ceitec'}"> + <ceitec:header title="${title}" reqURL="${reqURL}" cssLinks="${cssLinks}" baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + </c:when> + <c:when test="${theme eq 'europdx'}"> + <europdx:header title="${title}" reqURL="${reqURL}" cssLinks="${cssLinks}" baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + </c:when> + <c:when test="${theme eq 'muni'}"> + <muni:header title="${title}" reqURL="${reqURL}" cssLinks="${cssLinks}" baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + </c:when> + <c:otherwise> + <o:header title="${title}"/> + </c:otherwise> +</c:choose> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/headerBody.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/headerBody.tag new file mode 100644 index 000000000..6c6df4df3 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/headerBody.tag @@ -0,0 +1,14 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags/common" %> +<%@ attribute name="logoURL" required="true" %> + +<body> + + <div id="wrap"> + <c:if test="${ langsMap.size() > 1 }"> + <o:langbar lang="${lang}" langsMap="${langsMap}" reqURL="${reqURL}"/> + </c:if> + <div id="header"> + <img src="${logoURL}" alt="logo"> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/headerCssLinks.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/headerCssLinks.tag new file mode 100644 index 000000000..23666ade5 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/headerCssLinks.tag @@ -0,0 +1,7 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ attribute name="cssLinks" required="true" type="java.util.ArrayList<java.lang.String>" %> + +<c:forEach var="link" items="${cssLinks}"> + <link rel="stylesheet" type="text/css" href="${link}" /> +</c:forEach> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/headerInit.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/headerInit.tag new file mode 100644 index 000000000..7060d202d --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/headerInit.tag @@ -0,0 +1,22 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ attribute name="title" required="true" %> +<%@ attribute name="reqURL" required="true" %> +<%@ attribute name="baseURL" required="true" %> +<%@ attribute name="samlResourcesURL" required="true" %> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="${lang}" xml:lang="${lang}"> + +<head> + + <base href="${config.issuer}"> + <title>${config.topbarTitle} - ${title}</title> + + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0" /> + <meta name="robots" content="noindex, nofollow" /> + + <link rel="stylesheet" type="text/css" href="${samlResourcesURL}/resources/default.css" /> + <link rel="stylesheet" type="text/css" href="resources/css/customs.css"> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/langbar.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/langbar.tag new file mode 100644 index 000000000..89df64744 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/common/langbar.tag @@ -0,0 +1,34 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ attribute name="lang" required="true" %> +<%@ attribute name="langsMap" required="true" type="java.util.Map" %> +<%@ attribute name="reqURL" required="true" %> + +<c:set var="i" value="0"/> +<div id="languagebar_line"> + <div id="languagebar"> + <c:choose> + <c:when test="${fn:contains(reqURL, '?')}"> + <c:set var="requestURL" value="${reqURL}${'&lang='}"/> + </c:when> + <c:otherwise> + <c:set var="requestURL" value="${reqURL}${'?lang='}"/> + </c:otherwise> + </c:choose> + <c:forEach var="langEntry" items="${langsMap}"> + <c:choose> + <c:when test="${ langEntry.key.equalsIgnoreCase(lang)}"> + <c:out value="${langEntry.value}" /> + </c:when> + <c:otherwise> + <a href="${requestURL}${langEntry.key}">${langEntry.value}</a> + </c:otherwise> + </c:choose> + <c:if test="${ i < (langsMap.size() - 1) }"> + <c:out value=" | "/> + </c:if> + <c:set var="i" value="${ i + 1 }"/> + </c:forEach> + </div> +</div> \ No newline at end of file diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/copyright.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/copyright.tag new file mode 100644 index 000000000..605ff4616 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/copyright.tag @@ -0,0 +1,11 @@ +<%@ tag pageEncoding="UTF-8" import="cz.muni.ics.oidc.server.configurations.PerunOidcConfig" trimDirectiveWhitespaces="true" %> +<%@ tag import="org.springframework.web.context.support.WebApplicationContextUtils" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<c:if test="${ config.heartMode }"><span class="pull-left"><img src="resources/images/heart_mode.png" alt="HEART Mode" title="This server is running in HEART Compliance Mode" /></span> </c:if> +<% + PerunOidcConfig perunOidcConfig = WebApplicationContextUtils.getWebApplicationContext(application).getBean("perunOidcConfig", PerunOidcConfig.class); +%> +Powered by +<a href="https://github.com/CESNET/perun-mitreid">Perun MITREid</a> <span class="label"><%=perunOidcConfig.getPerunOIDCVersion()%></span> +<span class="pull-right">© 2017 The MIT Internet Trust Consortium.</span>. diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/elixir/footer.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/elixir/footer.tag new file mode 100644 index 000000000..d0d11980e --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/elixir/footer.tag @@ -0,0 +1,27 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ attribute name="js" required="false"%> +<%@ attribute name="baseURL" required="true"%> +<%@ attribute name="samlResourcesURL" required="true"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> +<jsp:useBean id="date" class="java.util.Date" /> + +<div id="footer"> + <div style="margin: 0 auto; max-width: 1000px;"> + <div style="float: left;"> + <img src="${samlResourcesURL}/module.php/elixir/res/img/logo_64.png" alt="ELIXIR Logo"> + </div> + <div style="float: left;"> + <p>ELIXIR, Welcome Trust Genome Campus, Hinxton, Cambridgeshire, CB10 1SD, UK +44 (0)1223 492-670 + <a href="mailto:info@elixir-europe.org">info@elixir-europe.org</a> + </p> + <p>Copyright © ELIXIR <fmt:formatDate value="${date}" pattern="yyyy" /> | + <a href="https://www.elixir-europe.org/legal/privacy">Privacy</a> | + <a href="https://www.elixir-europe.org/legal/cookies">Cookies</a> | + <a href="https://www.elixir-europe.org/legal/terms-of-use">Terms of use</a> + </p> + </div> + </div> +</div> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/elixir/header.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/elixir/header.tag new file mode 100644 index 000000000..33260a391 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/elixir/header.tag @@ -0,0 +1,22 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags/common" %> +<%@ attribute name="title" required="true" %> +<%@ attribute name="reqURL" required="true" %> +<%@ attribute name="baseURL" required="true" %> +<%@ attribute name="samlResourcesURL" required="true" %> +<%@ attribute name="cssLinks" required="true" type="java.util.ArrayList<java.lang.String>" %> + +<c:set var="logoURL" value="${samlResourcesURL}/module.php/elixir/res/img/logo_256.png"/> + +<o:headerInit title="${title}" reqURL="${reqURL}" baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}"/> + +<link rel="stylesheet" type="text/css" href="${samlResourcesURL}/module.php/elixir/res/bootstrap/css/bootstrap.min.css" /> +<link rel="stylesheet" type="text/css" href="${samlResourcesURL}/module.php/elixir/res/css/elixir.css" /> + +<o:headerCssLinks cssLinks="${cssLinks}"/> + +</head> + +<o:headerBody logoURL="${logoURL}"/> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/europdx/footer.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/europdx/footer.tag new file mode 100644 index 000000000..14fd3f1c7 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/europdx/footer.tag @@ -0,0 +1,35 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ attribute name="js" required="false"%> +<%@ attribute name="baseURL" required="true"%> +<%@ attribute name="samlResourcesURL" required="true"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> +<jsp:useBean id="date" class="java.util.Date" /> + +<div id="footer"> + <div class="row" style="margin: 0 auto; max-width: 1000px;"> + <div class="col-md-6" style="float: left"> + <img src="${samlResourcesURL}/module.php/europdx/res/img/eu_flag_128.png"> + <p>The EDIReX project has received funding from the European Union’s Horizon 2020 research and innovation programme, grant agreement no. #731105</p> + </div> + + <div class="col-md-6" style="float: right;"> + <ul> + <li> + <a href="http://www.twitter.com/EurOPDX"> Follow @EUROPDX</a> + </li> + <li> + <a href="https://europdx.eu/#"> TERMS OF USE</a> + </li> + </ul> + </div> + </div> + + <div class="row" style="text-align: center"> + <div class="col-md-12 copyright"> + <p> © 1991– 2019 | EuroPDX - <a href="mailto:contact@europdx.eu"> contact@europdx.eu </a></p> + </div> + </div> +</div> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/europdx/header.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/europdx/header.tag new file mode 100644 index 000000000..5866e05fe --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/europdx/header.tag @@ -0,0 +1,22 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags/common" %> +<%@ attribute name="title" required="true" %> +<%@ attribute name="reqURL" required="true" %> +<%@ attribute name="baseURL" required="true" %> +<%@ attribute name="samlResourcesURL" required="true" %> +<%@ attribute name="cssLinks" required="true" type="java.util.ArrayList<java.lang.String>" %> + +<c:set var="logoURL" value="${samlResourcesURL}/module.php/europdx/res/img/europdx_logo.png"/> + +<o:headerInit title="${title}" reqURL="${reqURL}" baseURL="${baseURL}" samlResourcesURL="${samlResourcesURL}" /> + +<link rel="stylesheet" type="text/css" href="${samlResourcesURL}/module.php/europdx/res/bootstrap/css/bootstrap.min.css" /> +<link rel="stylesheet" type="text/css" href="${samlResourcesURL}/module.php/europdx/res/css/europdx.css" /> + +<o:headerCssLinks cssLinks="${cssLinks}"/> + +</head> + +<o:headerBody logoURL="${logoURL}"/> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/footer.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/footer.tag similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/footer.tag rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/footer.tag diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/header.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/header.tag similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/header.tag rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/header.tag diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/muni/footer.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/muni/footer.tag new file mode 100644 index 000000000..8d0bc5487 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/muni/footer.tag @@ -0,0 +1,17 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> + + </div> + </div> +</main> + +<footer class="footer"> + <div class="row-main"> + <p class="footer__copyrights"> + ${langProps['masaryk_university']}<br /> + ${langProps['service']}${" "}<a href="https://it.muni.cz/sluzby/jednotne-prihlaseni-na-muni" target="_blank">${langProps['unified_login']}</a>${" "}${langProps['provided']}${" "}<a href="https://www.ics.muni.cz" target="_blank">${langProps['ics']}</a> + </p> + </div> +</footer> + +</body> +</html> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/muni/header.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/muni/header.tag new file mode 100644 index 000000000..a425f3c3a --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/muni/header.tag @@ -0,0 +1,84 @@ +<%@ tag pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags/common" %> +<%@ attribute name="title" required="true" %> +<%@ attribute name="reqURL" required="true" %> +<%@ attribute name="baseURL" required="true" %> +<%@ attribute name="samlResourcesURL" required="true" %> +<%@ attribute name="cssLinks" required="true" type="java.util.ArrayList<java.lang.String>" %> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html class="no-js touch no-touch" lang="${langProps['other_lang']}"> +<head> + <meta cahrset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta name="author" content="Masarykova univerzita" /> + + <title>${langProps['unified_login']} | ${title}</title> + + <link rel="stylesheet" type="text/css" href="https://id.muni.cz/simplesaml/module.php/muni/css/bootstrap.min.css"> + <link rel="stylesheet" type="text/css" href="https://id.muni.cz/simplesaml/module.php/muni/css/style-ie.css?1.2"> + <link rel="stylesheet" type="text/css" href="https://id.muni.cz/simplesaml/module.php/muni/css/style.css?1.2"> + <link rel="stylesheet" type="text/css" href="https://id.muni.cz/simplesaml/module.php/muni/css/style2.css?1.2"> + + <style type="text/css"> + .checkbox-wrapper { + float: left; + } + .attrname-formatter { + display: block; + margin-left: 2em !important; + } + </style> + + <o:headerCssLinks cssLinks="${cssLinks}"/> + +</head> + +<body> + <c:set var="alternateURL" value="${reqURL}&lang=${langProps['other_lang']}"/> + <p class="menu-accessibility"> + <a title="${langProps['go_to_login_title']}" accesskey="2" href="#main"> + ${langProps['go_to_login_text']} + </a> + </p> + <div class="header u-mb-0"> + <div class="row-main"> + <div class="header__wrap"> + <h1 class="header__logo"> + <img src="${samlResourcesURL}/module.php/${theme}/img/${langProps['img_name']}.png" + width="${langProps['img_width']}" height="${langProps['img_height']}" alt="${langProps['muni_logo']}"/> + </h1> + <div class="header__side"> + <div class="menu-lang" role="navigation"> + <p class="menu-lang__selected"> + <a href="${alternateURL}" rel="alternate" hreflang="${langProps['other_lang']}" + lang="${langProps['other_lang']}" class="menu-lang__selected__link"> + ${langProps['other_language']} + </a> + </p> + </div> + <nav class="menu-mobile" role="navigation"> + <div class="menu-mobile__wrap"> + <div class="row-main"> + <ul class="menu-mobile__list"> + <li class="menu-mobile__item"> + <a href="${alternateURL}" rel="alternate" hreflang="${langProps['other_lang']}" + class="menu-mobile__link menu-mobile__link--lang" lang="${langProps['other_lang']}"> + ${langProps['other_language']} + </a> + </li> + </ul> + </div> + </div> + </nav> + </div> + </div> + </div> + </div> + + <!-- END MU HEADER --> + <main class="main"> + <div class="box-hero box-hero--particles box-hero--login u-mb-0 u-pt-50"> + <div class="row-main"> + <div> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/navmenu.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/navmenu.tag similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/navmenu.tag rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/navmenu.tag diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/sidebar.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/sidebar.tag similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/sidebar.tag rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/sidebar.tag diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/topbar.tag b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/topbar.tag similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/topbar.tag rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/tags/topbar.tag diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/task-config.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/task-config.xml similarity index 54% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/task-config.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/task-config.xml index 2b7513328..4719b08e3 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/task-config.xml +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/task-config.xml @@ -22,17 +22,4 @@ xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> - <!-- Configuration for scheduled tasks --> - <task:scheduler id="taskScheduler" pool-size="10" /> - <task:executor id="taskExecutor" pool-size="5" /> - <task:annotation-driven scheduler="taskScheduler" executor="taskExecutor" /> - - <!-- Schedule the token service and approved site service to clear out expired tokens and sites every 5 minutes --> - <task:scheduled-tasks scheduler="taskScheduler"> - <task:scheduled ref="defaultOAuth2ProviderTokenService" method="clearExpiredTokens" fixed-delay="300000" initial-delay="600000"/> - <task:scheduled ref="defaultApprovedSiteService" method="clearExpiredSites" fixed-delay="300000" initial-delay="600000"/> - <task:scheduled ref="defaultOAuth2AuthorizationCodeService" method="clearExpiredAuthorizationCodes" fixed-delay="300000" initial-delay="600000"/> - <task:scheduled ref="defaultDeviceCodeService" method="clearExpiredDeviceCodes" fixed-delay="300000" initial-delay="600000"/> - </task:scheduled-tasks> - </beans> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/ui-config.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/ui-config.xml similarity index 96% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/ui-config.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/ui-config.xml index 99951d230..0dcd0250b 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/ui-config.xml +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/ui-config.xml @@ -31,7 +31,7 @@ <!-- This file allows you to define components to the UI --> - <bean class="org.mitre.openid.connect.config.UIConfiguration" id="uiConfiguration"> + <bean class="cz.muni.ics.openid.connect.config.UIConfiguration" id="uiConfiguration"> <property name="jsFiles"> <set> <value>resources/js/client.js</value> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/user-context.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/user-context.xml new file mode 100644 index 000000000..77013435c --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/user-context.xml @@ -0,0 +1,824 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Replaces (overlays) the same-name file from project org.server.openid-connect-server-webapp. +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:security="http://www.springframework.org/schema/security" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:aop="http://www.springframework.org/schema/aop" + xmlns:mvc="http://www.springframework.org/schema/mvc" + xsi:schemaLocation="http://www.springframework.org/schema/security + http://www.springframework.org/schema/security/spring-security.xsd + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context.xsd + http://www.springframework.org/schema/aop + http://www.springframework.org/schema/aop/spring-aop.xsd + http://www.springframework.org/schema/mvc + http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd"> + + <context:property-placeholder properties-ref="nonOverwrittenAttributeProperties" ignore-unresolvable="true" order="0"/> + <context:property-placeholder properties-ref="userAttrMappingsProperties" ignore-unresolvable="true" order="1"/> + <context:property-placeholder properties-ref="facilityAttrMappingsProperties" ignore-unresolvable="true" order="2"/> + <context:property-placeholder properties-ref="groupAttrMappingsProperties" ignore-unresolvable="true" order="3"/> + <context:property-placeholder properties-ref="voAttrMappingsProperties" ignore-unresolvable="true" order="4"/> + <context:property-placeholder properties-ref="resourceAttrMappingsProperties" ignore-unresolvable="true" order="5"/> + <context:property-placeholder properties-ref="coreProperties" order="6"/> + + <context:component-scan base-package="cz.muni.ics.oidc"/> + + <aop:aspectj-autoproxy proxy-target-class="true"/> + + <mvc:interceptors> + <mvc:interceptor> + <!-- Exclude APIs and other machine-facing endpoints from these interceptors --> + <mvc:mapping path="/**" /> + <mvc:exclude-mapping path="/token**"/> + <mvc:exclude-mapping path="/resources/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.JWKSetPublishingEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.DynamicClientRegistrationEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.ProtectedResourceRegistrationEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.UserInfoEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.RootController).API_URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.DeviceEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.IntrospectionEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.RevocationEndpoint).URL}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.IsTestSpController).MAPPING}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.AupController).URL}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedController).UNAPPROVED_MAPPING}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedController).UNAPPROVED_AUTHORIZATION}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedController).UNAPPROVED_ENSURE_VO_MAPPING}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedController).UNAPPROVED_IS_CESNET_ELIGIBLE_MAPPING}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedController).UNAPPROVED_NOT_IN_MANDATORY_VOS_GROUPS}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedController).UNAPPROVED_NOT_IN_PROD_VOS_GROUPS}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedController).UNAPPROVED_NOT_IN_TEST_VOS_GROUPS}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedController).UNAPPROVED_NOT_LOGGED_IN}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedController).UNAPPROVED_SPECIFIC_MAPPING}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedRegistrationController).REGISTRATION_CONTINUE_MAPPING}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedRegistrationController).REGISTRATION_FORM_MAPPING}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.PerunUnapprovedRegistrationController).REGISTRATION_FORM_SUBMIT_MAPPING}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.RegistrationController).CONTINUE_DIRECT_MAPPING}**" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.LogoutController).MAPPING_SUCCESS}" /> + <mvc:exclude-mapping path="#{T(cz.muni.ics.oidc.web.controllers.LoginController).MAPPING_FAILURE}" /> + <mvc:exclude-mapping path="/saml**" /> + <!-- Inject the UserInfo into the response --> + <ref bean="userInfoInterceptor" /> + </mvc:interceptor> + <mvc:interceptor> + <!-- Exclude APIs and other machine-facing endpoints from these interceptors --> + <mvc:mapping path="/**" /> + <mvc:exclude-mapping path="/token**"/> + <mvc:exclude-mapping path="/resources/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.JWKSetPublishingEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.DynamicClientRegistrationEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.ProtectedResourceRegistrationEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.UserInfoEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.openid.connect.web.RootController).API_URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.DeviceEndpoint).URL}/**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.IntrospectionEndpoint).URL}**" /> + <mvc:exclude-mapping path="/#{T(cz.muni.ics.oauth2.web.RevocationEndpoint).URL}**" /> + <!-- Inject the server configuration into the response --> + <ref bean="serverConfigInterceptor"/> + </mvc:interceptor> + </mvc:interceptors> + + <!-- default config values, by default override in file /etc/perun/perun-mitreid.properties --> + <bean id="defaultCoreProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties"> + <props> + <prop key="main.oidc.issuer.url">https://perun-dev.meta.zcu.cz/oidc/</prop> + <prop key="logo.image.url">resources/images/perun_24px.png</prop> + <prop key="topbar.title">Perun OIDC</prop> + <prop key="admins">3197,59835</prop> + <prop key="perun.adapter.callFallback">true</prop> + <prop key="fill.missing.user.attrs">true</prop> + <prop key="perun.adapter.primary">RPC</prop> + <!-- RPC --> + <prop key="perun.rpc.enabled">true</prop> + <prop key="perun.rpc.url">https://perun.elixir-czech.cz/krb/rpc</prop> + <prop key="perun.rpc.user">xxxxx</prop> + <prop key="perun.rpc.password">yyyyy</prop> + <prop key="perun.rpc.serializer">json</prop> + <!-- LDAP --> + <prop key="ldap.host">perun.cesnet.cz</prop> + <prop key="ldap.user">xxxxx</prop> + <prop key="ldap.password">yyyyyyy</prop> + <prop key="ldap.port">636</prop> + <prop key="ldap.starttls">true</prop> + <prop key="ldap.ssl">true</prop> + <prop key="ldap.password">yyyyyyy</prop> + <prop key="ldap.timeoutSecs">120</prop> + <prop key="ldap.baseDN">dc=perun,dc=cesnet,dc=cz</prop> + <prop key="ldap.allowUntrustedSsl">false</prop> + <!-- JDBC --> + <prop key="jdbc.driver">org.mariadb.jdbc.Driver</prop> + <prop key="jdbc.url">jdbc:mariadb://localhost:3306/oidc</prop> + <prop key="jdbc.user">oidc</prop> + <prop key="jdbc.password">oidc</prop> + <prop key="jdbc.platform">org.eclipse.persistence.platform.database.MySQLPlatform</prop> + <!-- SAML AUTH --> + <prop key="saml.entityID">https://login.cesnet.cz/oidc/</prop> + <prop key="saml.keystore.location">/etc/perun/perun-mitreid-saml-keystore.jks</prop> + <prop key="saml.keystore.password">pass</prop> + <prop key="saml.keystore.defaultKey">pass</prop> + <prop key="saml.keystore.defaultKeyPass">pass</prop> + <prop key="saml.idp.defaultIdpEntityId">https://login.cesnet.cz/idp/</prop> + <prop key="saml.idp.metadataLocation"/> <!-- i.e. /etc/perun/login-cesnet-metadata.xml --> + <prop key="saml.idp.metadataUrl"/> <!-- i.e. https://login.cesnet.cz/proxy/module.php/metadata --> + <prop key="saml.proxy.enabled">true</prop> + <prop key="saml.proxy.spEntityId">https://login.cesnet.cz/proxy/</prop> + <prop key="saml.acrs.reserverdPrefixes">urn:cesnet:</prop> + <prop key="saml.acrs.enableComparison">false</prop> + <!-- STATS JDBC --> + <prop key="stats.jdbc.url">jdbc:mariadb://localhost:3306/STATS</prop> + <prop key="stats.jdbc.user">user</prop> + <prop key="stats.jdbc.password">password</prop> + <!-- WEB INTERFACE --> + <prop key="web.theme">default</prop> + <prop key="web.langs">EN</prop> <!-- EN,CS,SK --> + <prop key="web.langs.customfiles.path">/etc/perun</prop> + <prop key="web.classes.path">/etc/perun/web/classes.properties</prop> + <prop key="web.baseURL">https://login.cesnet.cz/proxy</prop> + <prop key="email.contact">login@cesnet.cz</prop> + <!-- LOGIN --> + <prop key="idpFilters.askPerun.enabled">false</prop> + <prop key="registrar.url">https://perun-dev.cesnet.cz/allfed/registrar/</prop> + <prop key="proxy.extSource.name"/> + <prop key="proxy.base.url"/> + <prop key="proxy.login.url"/> + <prop key="proxy.logout.url"/> + <prop key="proxy.add_client_id_to_acrs">false</prop> + <!-- OIDC STUFF --> + <prop key="jwk">file:///etc/perun/perun-oidc-keystore.jwks</prop> + <prop key="id_token.scopes">openid,profile,email,phone,address</prop> + <prop key="custom.claims">organization,eppns</prop> + <prop key="accessTokenClaimsModifier">cz.muni.ics.oidc.server.PerunAccessTokenEnhancer.NoOpAccessTokenClaimsModifier</prop> + <prop key="force.regenerate.userinfo.custom.claims" /> + <prop key="force.regenerate.userinfo.standard.claims" /> + <!-- UES ATTRS --> + <prop key="ues.orgUrl.attr">urn:perun:ues:attribute-def:def:organizationURL</prop> + <prop key="ues.affiliations.attr">urn:perun:ues:attribute-def:def:affiliation</prop> + <!-- USERINFO MODIFIERS --> + <prop key="userInfo.modifiers"/> + <!-- REQUEST FILTERS --> + <prop key="filter.names">stats</prop> + <prop key="filter.stats.class">cz.muni.ics.oidc.server.filters.impl.ProxyStatisticsFilter</prop> + <prop key="filter.stats.idpNameAttributeName">sourceIdPName</prop> + <prop key="filter.stats.idpEntityIdAttributeName">sourceIdPEntityID</prop> + <prop key="filter.stats.statisticsTableName">statistics_per_user</prop> + <prop key="filter.stats.identityProvidersMapTableName">statistics_idp</prop> + <prop key="filter.stats.serviceProvidersMapTableName">statistics_sp</prop> + </props> + </property> + </bean> + + <bean id="coreProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties" ref="defaultCoreProperties"/> + <property name="locations"> + <list> + <!-- PASSED FROM POM.XML / MAVEN BUILD PROPS --> + <value>file://${config.location}/perun-mitreid.properties</value> + </list> + </property> + <property name="ignoreResourceNotFound" value="false"/> + </bean> + + <bean id="samlProperties" class="cz.muni.ics.oidc.saml.SamlProperties"> + <property name="entityID" value="${saml.idp.defaultIdpEntityId}"/> + <property name="keystoreLocation" value="${saml.keystore.location}"/> + <property name="keystorePassword" value="${saml.keystore.password}"/> + <property name="keystoreDefaultKey" value="${saml.keystore.defaultKey}"/> + <property name="keystoreDefaultKeyPassword" value="${saml.keystore.defaultKeyPass}"/> + <property name="defaultIdpEntityId" value="${saml.idp.defaultIdpEntityId}"/> + <property name="idpMetadataFile" value="${saml.idp.metadataLocation}"/> + <property name="idpMetadataUrl" value="${saml.idp.metadataUrl}"/> + <property name="acrReservedPrefixes" value="#{'${saml.acrs.reserverdPrefixes}'.split('\s*,\s*')}"/> + </bean> + + <bean id="nonOverwrittenAttributeProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties"> + <props> + <prop key="user.attribute_names.fixedList">openid_sub,profile_preferred_username,profile_given_name,profile_middle_name,profile_family_name,profile_name,profile_zoneinfo,profile_locale,email_email,address_address_formatted,phone_phone,aups</prop> + <prop key="facility.attribute_names.fixedList">checkGroupMembership,allowRegistration,registrationUrl,dynamicRegistration,clientId,voShortNames,wayfFilter,wayfEFilter,requestedAups,capabilities,testSp</prop> + <prop key="group.attribute_names.fixedList"/> + <prop key="vo.attribute_names.fixedList">aup</prop> + <prop key="resource.attribute_names.fixedList">capabilities</prop> + </props> + </property> + </bean> + + <bean id="defaultUserAttrProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties"> + <props> + <prop key="user.attribute_names.customList"/> + <!-- ATTRIBUTES MAPPINGS --> + <prop key="openid_sub.mapping.ldap">login;x-ns-einfraid-persistent-shadow</prop> + <prop key="openid_sub.mapping.rpc">urn:perun:user:attribute-def:core:id</prop> + <prop key="openid_sub.type">STRING</prop> + <prop key="profile_preferred_username.mapping.ldap">login;x-ns-einfra</prop> + <prop key="profile_preferred_username.mapping.rpc">urn:perun:user:attribute-def:def:login-namespace:einfra</prop> + <prop key="profile_preferred_username.type">STRING</prop> + <prop key="profile_given_name.mapping.ldap">givenName</prop> + <prop key="profile_given_name.mapping.rpc">urn:perun:user:attribute-def:core:firstName</prop> + <prop key="profile_given_name.type">STRING</prop> + <prop key="profile_middle_name.mapping.ldap">middleName</prop> + <prop key="profile_middle_name.mapping.rpc">urn:perun:user:attribute-def:core:middleName</prop> + <prop key="profile_middle_name.type">STRING</prop> + <prop key="profile_family_name.mapping.ldap">sn</prop> + <prop key="profile_family_name.mapping.rpc">urn:perun:user:attribute-def:core:lastName</prop> + <prop key="profile_family_name.type">STRING</prop> + <prop key="profile_name.mapping.ldap">displayName</prop> + <prop key="profile_name.mapping.rpc">urn:perun:user:attribute-def:core:displayName</prop> + <prop key="profile_name.type">STRING</prop> + <prop key="profile_zoneinfo.mapping.ldap">timezone</prop> + <prop key="profile_zoneinfo.mapping.rpc">urn:perun:user:attribute-def:def:timezone</prop> + <prop key="profile_zoneinfo.type">STRING</prop> + <prop key="profile_locale.mapping.ldap">preferredLanguage</prop> + <prop key="profile_locale.mapping.rpc">urn:perun:user:attribute-def:def:preferredLanguage</prop> + <prop key="profile_locale.type">STRING</prop> + <prop key="email_email.mapping.ldap">preferredMail</prop> + <prop key="email_email.mapping.rpc">urn:perun:user:attribute-def:def:preferredMail</prop> + <prop key="email_email.type">STRING</prop> + <prop key="phone_phone.mapping.ldap">telephoneNumber</prop> + <prop key="phone_phone.mapping.rpc">urn:perun:user:attribute-def:def:phone</prop> + <prop key="phone_phone.type">STRING</prop> + <prop key="address_address_formatted.mapping.ldap">postalAddress</prop> + <prop key="address_address_formatted.mapping.rpc">urn:perun:user:attribute-def:def:address</prop> + <prop key="address_address_formatted.type">STRING</prop> + <prop key="aups.mapping.ldap">aups</prop> + <prop key="aups.mapping.rpc">urn:perun:user:attribute-def:def:aups</prop> + <prop key="aups.type">MAP_KEY_VALUE</prop> + <prop key="aups.separator">=</prop> + </props> + </property> + </bean> + + <bean id="userAttrMappingsProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties" ref="defaultUserAttrProperties" /> + <property name="locations"> + <list> + <!-- PASSED FROM POM.XML / MAVEN BUILD PROPS --> + <value>file://${config.location}/user-attribute-mappings.properties</value> + </list> + </property> + <property name="ignoreResourceNotFound" value="true"/> + </bean> + + <bean id="defaultFacilityAttrProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties"> + <props> + <prop key="facility.attribute_names.customList"/> + <!-- ATTRIBUTES MAPPINGS --> + <prop key="checkGroupMembership.mapping.ldap">checkGroupMembership</prop> + <prop key="checkGroupMembership.mapping.rpc">urn:perun:facility:attribute-def:def:checkGroupMembership</prop> + <prop key="checkGroupMembership.type">BOOLEAN</prop> + <prop key="allowRegistration.mapping.ldap">allowRegistration</prop> + <prop key="allowRegistration.mapping.rpc">urn:perun:facility:attribute-def:def:allowRegistration</prop> + <prop key="allowRegistration.type">BOOLEAN</prop> + <prop key="registrationUrl.mapping.ldap">registrationURL</prop> + <prop key="registrationUrl.mapping.rpc">urn:perun:facility:attribute-def:def:registrationURL</prop> + <prop key="registrationUrl.type">STRING</prop> + <prop key="dynamicRegistration.mapping.ldap">dynamicRegistration</prop> + <prop key="dynamicRegistration.mapping.rpc">urn:perun:facility:attribute-def:def:dynamicRegistration</prop> + <prop key="dynamicRegistration.type">BOOLEAN</prop> + <prop key="clientId.mapping.ldap">OIDCClientID</prop> + <prop key="clientId.mapping.rpc">urn:perun:facility:attribute-def:def:OIDCClientID</prop> + <prop key="clientId.type">STRING</prop> + <prop key="voShortNames.mapping.ldap">voShortNames</prop> + <prop key="voShortNames.mapping.rpc">urn:perun:facility:attribute-def:virt:voShortNames</prop> + <prop key="voShortNames.type">ARRAY</prop> + <prop key="wayfFilter.mapping.ldap">wayfFilter</prop> + <prop key="wayfFilter.mapping.rpc">urn:perun:facility:attribute-def:def:wayfFilter</prop> + <prop key="wayfFilter.type">STRING</prop> + <prop key="wayfEFilter.mapping.ldap">wayfEFilter</prop> + <prop key="wayfEFilter.mapping.rpc">urn:perun:facility:attribute-def:def:wayfEFilter</prop> + <prop key="wayfEFilter.type">STRING</prop> + <prop key="requestedAups.mapping.ldap">requiredAups</prop> + <prop key="requestedAups.mapping.rpc">urn:perun:facility:attribute-def:def:reqAups</prop> + <prop key="requestedAups.type">ARRAY</prop> + <prop key="capabilities.mapping.ldap">capabilities</prop> + <prop key="capabilities.mapping.rpc">urn:perun:facility:attribute-def:def:capabilities</prop> + <prop key="capabilities.type">ARRAY</prop> + <prop key="testSp.mapping.ldap">isTestSp</prop> + <prop key="testSp.mapping.rpc">urn:perun:facility:attribute-def:def:isTestSp</prop> + <prop key="testSp.type">BOOLEAN</prop> + </props> + </property> + </bean> + + <bean id="facilityAttrMappingsProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties" ref="defaultFacilityAttrProperties" /> + <property name="locations"> + <list> + <!-- PASSED FROM POM.XML / MAVEN BUILD PROPS --> + <value>file://${config.location}/facility-attribute-mappings.properties</value> + </list> + </property> + <property name="ignoreResourceNotFound" value="true"/> + </bean> + + <bean id="defaultGroupAttrProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties"> + <props> + <prop key="group.attribute_names.customList"/> + </props> + </property> + </bean> + + <bean id="groupAttrMappingsProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties" ref="defaultGroupAttrProperties" /> + <property name="locations"> + <list> + <!-- PASSED FROM POM.XML / MAVEN BUILD PROPS --> + <value>file://${config.location}/group-attribute-mappings.properties</value> + </list> + </property> + <property name="ignoreResourceNotFound" value="true"/> + </bean> + + <bean id="defaultVoAttrProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties"> + <props> + <prop key="vo.attribute_names.customList"/> + <!-- ATTRIBUTES MAPPINGS --> + <prop key="aup.mapping.ldap">aup</prop> + <prop key="aup.mapping.rpc">urn:perun:vo:attribute-def:def:aup</prop> + <prop key="aup.type">LARGE_STRING</prop> + </props> + </property> + </bean> + + <bean id="voAttrMappingsProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties" ref="defaultVoAttrProperties" /> + <property name="locations"> + <list> + <!-- PASSED FROM POM.XML / MAVEN BUILD PROPS --> + <value>file://${config.location}/vo-attribute-mappings.properties</value> + </list> + </property> + <property name="ignoreResourceNotFound" value="true"/> + </bean> + + <bean id="defaultResourceAttrProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties"> + <props> + <prop key="resource.attribute_names.customList"/> + <!-- ATTRIBUTES MAPPINGS --> + <prop key="capabilities.mapping.ldap">capabilities</prop> + <prop key="capabilities.mapping.rpc">urn:perun:resource:attribute-def:def:capabilities</prop> + <prop key="capabilities.type">ARRAY</prop> + </props> + </property> + </bean> + + <bean id="resourceAttrMappingsProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> + <property name="properties" ref="defaultResourceAttrProperties" /> + <property name="locations"> + <list> + <!-- PASSED FROM POM.XML / MAVEN BUILD PROPS --> + <value>file://${config.location}/resource-attribute-mappings.properties</value> + </list> + </property> + <property name="ignoreResourceNotFound" value="true"/> + </bean> + + <!-- defines our own user info service --> + <bean id="userInfoService" primary="true" class="cz.muni.ics.oidc.server.userInfo.PerunUserInfoService"> + <property name="perunAdapter" ref="perunAdapter"/> + <property name="subAttribute" value="openid_sub"/> + <property name="preferredUsernameAttribute" value="profile_preferred_username"/> + <property name="givenNameAttribute" value="profile_given_name"/> + <property name="familyNameAttribute" value="profile_family_name"/> + <property name="middleNameAttribute" value="profile_middle_name"/> + <property name="fullNameAttribute" value="profile_name"/> + <property name="emailAttribute" value="email_email"/> + <property name="addressAttribute" value="address_address_formatted"/> + <property name="phoneAttribute" value="phone_phone"/> + <property name="zoneinfoAttribute" value="profile_zoneinfo"/> + <property name="localeAttribute" value="profile_locale"/> + <property name="properties" ref="coreProperties"/> + <property name="customClaimNames" value="#{'${custom.claims}'.split('\s*,\s*')}"/> + <property name="forceRegenerateUserinfoCustomClaims" value="#{'${force.regenerate.userinfo.custom.claims}'.split('\s*,\s*')}"/> + <property name="forceRegenerateUserinfoStandardClaims" value="#{'${force.regenerate.userinfo.standard.claims}'.split('\s*,\s*')}"/> + </bean> + + <!-- replaces default translation service with our own for custom scope with custom claims. --> + <bean id="scopeClaimTranslator" primary="true" class="cz.muni.ics.oidc.server.PerunScopeClaimTranslationService"> + <property name="perunUserInfoService" ref="userInfoService"/> + </bean> + + <bean id="introspectionResultAssembler" class="cz.muni.ics.oidc.server.PerunIntrospectionResultAssembler" primary="true"> + <constructor-arg name="configBean" ref="configBean"/> + <constructor-arg name="translator" ref="scopeClaimTranslator"/> + </bean> + + <bean id="perunOidcConfig" class="cz.muni.ics.oidc.server.configurations.PerunOidcConfig"> + <property name="rpcEnabled" value="${perun.rpc.enabled}"/> + <property name="rpcUrl" value="${perun.rpc.url}"/> + <property name="configBean" ref="configBean"/> + <property name="jwk" value="${jwk}"/> + <property name="jdbcUrl" value="${jdbc.url}"/> + <property name="theme" value="${web.theme}"/> + <property name="samlLoginURL" value="${proxy.login.url}"/> + <property name="samlLogoutURL" value="${proxy.logout.url}"/> + <property name="samlResourcesURL" value="${proxy.base.url}"/> + <property name="baseURL" value="${web.baseURL}"/> + <property name="registrarUrl" value="${registrar.url}"/> + <property name="fillMissingUserAttrs" value="${fill.missing.user.attrs}"/> + <property name="askPerunForIdpFiltersEnabled" value="${idpFilters.askPerun.enabled}"/> + <property name="proxyExtSourceName" value="${proxy.extSource.name}"/> + <property name="idTokenScopes" value="#{'${id_token.scopes}'.split('\s*,\s*')}"/> + <property name="availableLangs" value="#{'${web.langs}'.split('\s*,\s*')}"/> + <property name="localizationFilesPath" value="${web.langs.customfiles.path}"/> + <property name="webClassesFilePath" value="${web.classes.path}"/> + <property name="emailContact" value="${email.contact}"/> + <property name="addClientIdToAcrs" value="${proxy.add_client_id_to_acrs}"/> + </bean> + + <bean id="facilityAttrsConfig" class="cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig"> + <property name="checkGroupMembershipAttr" value="checkGroupMembership" /> + <property name="allowRegistrationAttr" value="allowRegistration" /> + <property name="registrationURLAttr" value="registrationURL" /> + <property name="dynamicRegistrationAttr" value="dynamicRegistration" /> + <property name="voShortNamesAttr" value="voShortNames" /> + <property name="wayfFilterAttr" value="wayfFilter" /> + <property name="wayfEFilterAttr" value="wayfEFilter" /> + <property name="testSpAttr" value="testSp" /> + </bean> + + <!-- authentication --> + + <!--suppress SpringXmlModelInspection --> + <security:http auto-config="false" + use-expressions="true" + entry-point-ref="samlEntryPoint" + create-session="always" + authentication-manager-ref="authenticationManager"> + <security:csrf disabled="true"/> + <security:intercept-url pattern="/saml/**" access="permitAll()"/> + <security:intercept-url pattern="/logout" access="permitAll()"/> + <security:intercept-url pattern="#{T(cz.muni.ics.oidc.web.controllers.LogoutController).MAPPING_SUCCESS}" access="permitAll()"/> + <security:intercept-url pattern="#{T(cz.muni.ics.oidc.web.controllers.LoginController).MAPPING_FAILURE}" access="permitAll()"/> + <security:intercept-url pattern="/**" access="hasRole('ROLE_USER')"/> + <security:custom-filter ref="mdcMuFilter" before="FIRST"/> + <security:custom-filter ref="metadataGeneratorFilter" before="CHANNEL_FILTER"/> + <security:custom-filter ref="clearSessionFilter" after="CHANNEL_FILTER"/> + <security:custom-filter ref="samlFilter" before="CSRF_FILTER"/> + <security:custom-filter ref="samlFilter" after="BASIC_AUTH_FILTER"/> + <security:custom-filter ref="callPerunFiltersFilter" before="LAST"/> + <security:logout logout-url="/saml/logout"/> + </security:http> + + <security:authentication-manager id="authenticationManager"> + <security:authentication-provider ref="authenticationProvider"/> + </security:authentication-manager> + + <bean id="mdcMuFilter" class="cz.muni.ics.oidc.server.filters.impl.MultiMDCFilter"/> + + <!-- SAML --> + + <bean id="clearSessionFilter" class="cz.muni.ics.oidc.saml.SamlInvalidateSessionFilter"> + <constructor-arg name="pattern" value="/authorize**"/> + <constructor-arg name="oidcIssuer" value="${main.oidc.issuer.url}"/> + <constructor-arg name="idpEntityId" value="${saml.idp.defaultIdpEntityId}"/> + <constructor-arg name="proxyEnabled" value="${saml.proxy.enabled}"/> + <constructor-arg name="proxySpEntityId" value="${saml.proxy.spEntityId}"/> + <constructor-arg name="contextLogoutHandler" ref="logoutHandler"/> + </bean> + <bean id="samlDiscovery" class="org.springframework.security.saml.SAMLDiscovery"> + <property name="contextProvider" ref="samlContextProvider"/> + <property name="samlEntryPoint" ref="samlEntryPoint"/> + <property name="metadata" ref="metadata"/> + </bean> + + <bean id="successRedirectHandler" class="cz.muni.ics.oidc.saml.PerunSamlAuthenticationSuccessHandler"> + <property name="defaultTargetUrl" value="#{T(cz.muni.ics.oidc.web.controllers.LoginController).MAPPING_SUCCESS}"/> + </bean> + + <bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> + <property name="defaultFailureUrl" value="#{T(cz.muni.ics.oidc.web.controllers.LoginController).MAPPING_FAILURE}"/> + <property name="useForward" value="true"/> + </bean> + + <bean id="successLogoutHandler" class="cz.muni.ics.oidc.saml.PerunOidcLogoutSuccessHandler"> + <property name="defaultTargetUrl" value="#{T(cz.muni.ics.oidc.web.controllers.LogoutController).MAPPING_SUCCESS}"/> + <property name="targetUrlParameter" value="#{T(cz.muni.ics.oidc.server.filters.PerunFilterConstants).PARAM_TARGET}"/> + </bean> + + <bean id="logoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"> + <property name="clearAuthentication" value="true"/> + <property name="invalidateHttpSession" value="true"/> + </bean> + + <bean id="samlLogoutProcessingFilter" class="org.springframework.security.saml.SAMLLogoutProcessingFilter"> + <constructor-arg name="logoutSuccessHandler" ref="successLogoutHandler"/> + <constructor-arg name="handlers" ref="logoutHandler"/> + </bean> + + <bean id="samlLogoutFilter" class="org.springframework.security.saml.SAMLLogoutFilter"> + <constructor-arg name="logoutSuccessHandler" ref="successLogoutHandler"/> + <constructor-arg name="localHandler" ref="logoutHandler"/> + <constructor-arg name="globalHandlers" ref="logoutHandler"/> + </bean> + + <bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager"> + <constructor-arg name="storeFile"> + <bean class="org.springframework.core.io.FileSystemResource"> + <constructor-arg name="path" value="${saml.keystore.location}"/> + </bean> + </constructor-arg> + <constructor-arg name="storePass" value="${saml.keystore.password}"/> + <constructor-arg name="passwords"> + <map> + <entry key="${saml.keystore.defaultKey}" value="${saml.keystore.defaultKeyPass}"/> + </map> + </constructor-arg> + <constructor-arg name="defaultKey" value="${saml.keystore.defaultKey}"/> + </bean> + + <bean id="extendedMetadata" class="org.springframework.security.saml.metadata.ExtendedMetadata"> + <property name="idpDiscoveryEnabled" value="false"/> + </bean> + + <bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter"> + <constructor-arg name="generator"> + <bean class="org.springframework.security.saml.metadata.MetadataGenerator"> + <property name="includeDiscoveryExtension" value="false"/> + <property name="entityId" value="${saml.entityID}"/> + <property name="extendedMetadata" ref="extendedMetadata"/> + <property name="wantAssertionSigned" value="true"/> + <property name="requestSigned" value="true"/> + </bean> + </constructor-arg> + <property name="normalizeBaseUrl" value="true"/> + </bean> + + <bean id="metadataDisplayFilter" class="org.springframework.security.saml.metadata.MetadataDisplayFilter"/> + + <bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager"> + <property name="defaultIDP" value="${saml.idp.defaultIdpEntityId}"/> + <property name="refreshCheckInterval" value="60000"/> + <property name="refreshRequired" value="false"/> + <constructor-arg name="providers"> + <list> + <ref bean="idpMetadata"/> + </list> + </constructor-arg> + </bean> + + <bean id="parserPool" class="org.opensaml.xml.parse.StaticBasicParserPool" init-method="initialize"/> + + <bean id="parserPoolHolder" class="org.springframework.security.saml.parser.ParserPoolHolder"/> + + <bean id="processor" class="org.springframework.security.saml.processor.SAMLProcessorImpl"> + <constructor-arg name="bindings"> + <list> + <bean id="httpPostBinding" class="org.springframework.security.saml.processor.HTTPPostBinding"> + <constructor-arg name="parserPool" ref="parserPool"/> + <constructor-arg name="velocityEngine" value="#{T(org.springframework.security.saml.util.VelocityFactory).getEngine()}"/> + </bean> + <bean id="httpRedirectDeflateBinding" class="org.springframework.security.saml.processor.HTTPRedirectDeflateBinding"> + <constructor-arg name="parserPool" ref="parserPool"/> + </bean> + </list> + </constructor-arg> + </bean> + + <bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter"> + <property name="authenticationManager" ref="authenticationManager"/> + <property name="authenticationSuccessHandler" ref="successRedirectHandler"/> + <property name="authenticationFailureHandler" ref="authenticationFailureHandler"/> + </bean> + + <bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy"> + <constructor-arg name="filterChains"> + <list> + <bean class="org.springframework.security.web.DefaultSecurityFilterChain"> + <constructor-arg name="requestMatcher"> + <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"> + <constructor-arg name="pattern" + value="#{T(org.springframework.security.saml.metadata.MetadataDisplayFilter).FILTER_URL}/**"/> + </bean> + </constructor-arg> + <constructor-arg name="filters"> + <list> + <ref bean="metadataDisplayFilter"/> + </list> + </constructor-arg> + </bean> + <bean class="org.springframework.security.web.DefaultSecurityFilterChain"> + <constructor-arg name="requestMatcher"> + <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"> + <constructor-arg name="pattern" + value="#{T(org.springframework.security.saml.SAMLProcessingFilter).FILTER_URL}"/> + </bean> + </constructor-arg> + <constructor-arg name="filters"> + <list> + <ref bean="samlWebSSOProcessingFilter"/> + </list> + </constructor-arg> + </bean> + <bean class="org.springframework.security.web.DefaultSecurityFilterChain"> + <constructor-arg name="requestMatcher"> + <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"> + <constructor-arg name="pattern" + value="#{T(org.springframework.security.saml.SAMLDiscovery).FILTER_URL}"/> + </bean> + </constructor-arg> + <constructor-arg name="filters"> + <list> + <ref bean="samlDiscovery"/> + </list> + </constructor-arg> + </bean> + <bean class="org.springframework.security.web.DefaultSecurityFilterChain"> + <constructor-arg name="requestMatcher"> + <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"> + <constructor-arg name="pattern" + value="#{T(org.springframework.security.saml.SAMLEntryPoint).FILTER_URL}"/> + </bean> + </constructor-arg> + <constructor-arg name="filters"> + <list> + <ref bean="samlEntryPoint"/> + </list> + </constructor-arg> + </bean> + <bean class="org.springframework.security.web.DefaultSecurityFilterChain"> + <constructor-arg name="requestMatcher"> + <bean class="org.springframework.security.web.util.matcher.OrRequestMatcher"> + <constructor-arg name="requestMatchers"> + <list> + <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"> + <constructor-arg name="pattern" + value="#{T(org.springframework.security.saml.SAMLLogoutFilter).FILTER_URL}"/> + </bean> + <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"> + <constructor-arg name="pattern" value="/logout"/> + </bean> + </list> + </constructor-arg> + </bean> + </constructor-arg> + <constructor-arg name="filters"> + <list> + <ref bean="samlLogoutFilter"/> + </list> + </constructor-arg> + </bean> + <bean class="org.springframework.security.web.DefaultSecurityFilterChain"> + <constructor-arg name="requestMatcher"> + <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"> + <constructor-arg name="pattern" value="#{T(org.springframework.security.saml.SAMLLogoutProcessingFilter).FILTER_URL}/**"/> + </bean> + </constructor-arg> + <constructor-arg name="filters"> + <list> + <ref bean="samlLogoutProcessingFilter"/> + </list> + </constructor-arg> + </bean> + </list> + </constructor-arg> + </bean> + + <bean id="webSSOProfileOptions" class="org.springframework.security.saml.websso.WebSSOProfileOptions"> + <property name="includeScoping" value="false"/> + </bean> + + <bean id="samlEntryPoint" class="cz.muni.ics.oidc.saml.PerunSamlEntryPoint"> + <property name="defaultProfileOptions" ref="webSSOProfileOptions"/> + </bean> + + <bean id="samlContextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl"/> + + <bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger"> + <property name="logMessagesOnException" value="true"/> + <property name="logErrors" value="true"/> + </bean> + + <bean id="singleLogoutProfile" class="org.springframework.security.saml.websso.SingleLogoutProfileImpl"/> + + <bean id="webSSOprofileConsumer" class="cz.muni.ics.oidc.saml.PerunWebSSOProfileConsumerImpl"> + <property name="enableComparison" value="${saml.acrs.enableComparison}"/> + <property name="reservedPrefixes" value="#{'${saml.acrs.reserverdPrefixes}'.split('\s*,\s*')}"/> + <property name="maxAuthenticationAge" value="360"/> + </bean> + + <bean id="webSSOprofile" class="org.springframework.security.saml.websso.WebSSOProfileImpl"/> + + <bean id="hokWebSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/> + + <bean id="samlUserDetailsService" class="cz.muni.ics.oidc.saml.PerunSamlUserDetailsService"/> + + <bean id="authenticationProvider" class="cz.muni.ics.oidc.saml.PerunSamlAuthenticationProvider"> + <constructor-arg name="adminIds" value="#{'${admins}'.split('\s*,\s*')}"/> + </bean> + + <bean class="org.springframework.security.saml.SAMLBootstrap"/> + + <!-- END SAML --> + + <bean id="accessTokenClaimsModifier" class="${accessTokenClaimsModifier}"/> + + <bean id="tokenEnhancer" class="cz.muni.ics.oidc.server.PerunAccessTokenEnhancer" primary="true"> + <property name="accessTokenClaimsModifier" ref="accessTokenClaimsModifier"/> + <constructor-arg name="configBean" ref="configBean"/> + <constructor-arg name="clientService" ref="defaultOAuth2ClientDetailsEntityService"/> + <constructor-arg name="jwtService" ref="defaultsignerService"/> + <constructor-arg name="connectTokenService" ref="oidcTokenService"/> + <constructor-arg name="userInfoService" ref="userInfoService"/> + </bean> + + <bean id="oidcTokenService" class="cz.muni.ics.oidc.server.PerunOIDCTokenService" primary="true"/> + + <bean id="callPerunFiltersFilter" class="cz.muni.ics.oidc.server.filters.CallPerunFiltersFilter"/> + + <bean id="localization" class="cz.muni.ics.oidc.web.langs.Localization"> + <constructor-arg name="perunOidcConfig" ref="perunOidcConfig"/> + </bean> + + <bean id="htmlClasses" class="cz.muni.ics.oidc.web.WebHtmlClasses"> + <constructor-arg name="perunOidcConfig" ref="perunOidcConfig"/> + </bean> + + <!-- communicates with Perun --> + + <bean id="perunConnectorRpc" class="cz.muni.ics.oidc.server.connectors.PerunConnectorRpc"> + <constructor-arg name="perunUrl" value="${perun.rpc.url}"/> + <constructor-arg name="perunUser" value="${perun.rpc.user}"/> + <constructor-arg name="perunPassword" value="${perun.rpc.password}"/> + <constructor-arg name="enabled" value="${perun.rpc.enabled}"/> + <constructor-arg name="serializer" value="${perun.rpc.serializer}"/> + </bean> + + <bean id="perunAdapterMethodsRpc" class="cz.muni.ics.oidc.server.adapters.impl.PerunAdapterRpc"> + <property name="connectorRpc" ref="perunConnectorRpc"/> + <property name="oidcClientIdAttr" value="clientId" /> + <property name="oidcCheckMembershipAttr" value="checkGroupMembership"/> + <property name="affiliationsAttr" value="${ues.affiliations.attr}"/> + <property name="orgUrlAttr" value="${ues.orgUrl.attr}"/> + </bean> + + <bean id="perunConnectorLdap" class="cz.muni.ics.oidc.server.connectors.PerunConnectorLdap"> + <constructor-arg name="ldapHost" value="${ldap.host}"/> + <constructor-arg name="ldapUser" value="${ldap.user}"/> + <constructor-arg name="ldapPassword" value="${ldap.password}"/> + <constructor-arg name="port" value="${ldap.port}"/> + <constructor-arg name="useTLS" value="${ldap.starttls}"/> + <constructor-arg name="useSSL" value="${ldap.ssl}"/> + <constructor-arg name="timeoutSecs" value="${ldap.timeoutSecs}"/> + <constructor-arg name="baseDN" value="${ldap.baseDN}"/> + <constructor-arg name="allowUntrustedSsl" value="${ldap.allowUntrustedSsl}"/> + </bean> + + <bean id="perunAdapterMethodsLdap" class="cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdap"> + <property name="connectorLdap" ref="perunConnectorLdap"/> + <property name="oidcClientIdAttr" value="clientId" /> + <property name="oidcCheckMembershipAttr" value="checkGroupMembership"/> + </bean> + + <bean id="userAttributesMappingService" class="cz.muni.ics.oidc.server.AttributeMappingsService"> + <constructor-arg name="attrIdentifiersFixed" value="#{'${user.attribute_names.fixedList}'.split('\s*,\s*')}" /> + <constructor-arg name="attrIdentifiersCustom" value="#{'${user.attribute_names.customList}'.split('\s*,\s*')}" /> + <constructor-arg name="attrMappingsProperties" ref="userAttrMappingsProperties" /> + </bean> + + <bean id="facilityAttributesMappingService" class="cz.muni.ics.oidc.server.AttributeMappingsService"> + <constructor-arg name="attrIdentifiersFixed" value="#{'${facility.attribute_names.fixedList}'.split('\s*,\s*')}" /> + <constructor-arg name="attrIdentifiersCustom" value="#{'${facility.attribute_names.customList}'.split('\s*,\s*')}" /> + <constructor-arg name="attrMappingsProperties" ref="facilityAttrMappingsProperties" /> + </bean> + + <bean id="groupAttributesMappingService" class="cz.muni.ics.oidc.server.AttributeMappingsService"> + <constructor-arg name="attrIdentifiersFixed" value="#{'${group.attribute_names.fixedList}'.split('\s*,\s*')}" /> + <constructor-arg name="attrIdentifiersCustom" value="#{'${group.attribute_names.customList}'.split('\s*,\s*')}" /> + <constructor-arg name="attrMappingsProperties" ref="groupAttrMappingsProperties" /> + </bean> + + <bean id="voAttributesMappingService" class="cz.muni.ics.oidc.server.AttributeMappingsService"> + <constructor-arg name="attrIdentifiersFixed" value="#{'${vo.attribute_names.fixedList}'.split('\s*,\s*')}" /> + <constructor-arg name="attrIdentifiersCustom" value="#{'${vo.attribute_names.customList}'.split('\s*,\s*')}" /> + <constructor-arg name="attrMappingsProperties" ref="voAttrMappingsProperties" /> + </bean> + + <bean id="resourceAttributesMappingService" class="cz.muni.ics.oidc.server.AttributeMappingsService"> + <constructor-arg name="attrIdentifiersFixed" value="#{'${resource.attribute_names.fixedList}'.split('\s*,\s*')}" /> + <constructor-arg name="attrIdentifiersCustom" value="#{'${resource.attribute_names.customList}'.split('\s*,\s*')}" /> + <constructor-arg name="attrMappingsProperties" ref="resourceAttrMappingsProperties" /> + </bean> + + <bean id="perunAdapter" class="cz.muni.ics.oidc.server.adapters.impl.PerunAdapterImpl"> + <property name="adapterLdap" ref="perunAdapterMethodsLdap"/> + <property name="adapterRpc" ref="perunAdapterMethodsRpc"/> + <property name="adapterFallback" ref="perunAdapterMethodsRpc"/> + <property name="adapterPrimary" ref="#{ '${perun.adapter.primary}' == 'LDAP' ? 'perunAdapterMethodsLdap' : 'perunAdapterMethodsRpc'}"/> + <property name="callFallback" value="${perun.adapter.callFallback}"/> + </bean> + +</beans> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/about.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/about.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/about.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/about.jsp diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/approve.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/approve.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/approve.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/approve.jsp diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/approveDevice.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/approveDevice.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/approveDevice.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/approveDevice.jsp diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/aup.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/aup.jsp new file mode 100644 index 000000000..c90793e5d --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/aup.jsp @@ -0,0 +1,39 @@ +<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> + +<% + +List<String> cssLinks = new ArrayList<>(); + +pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${langProps['aup_header']}" reqURL="${reqURL}" baseURL="${baseURL}" cssLinks="${cssLinks}" theme="${theme}"/> + +<h1>${langProps['aup_header']}</h1> + +</div> <%-- header --%> + +<div id="content"> + <h3>${langProps['must_agree_aup']}</h3> + <form method="POST" action=""> + <c:forEach var="aup" items="${newAups}"> + <div> + <p style="font-size: 16px; padding: 0; margin: 0;">${langProps['org_vo']} ${" "}<strong><c:out value="${aup.key}"/></strong></p> + <p>${langProps['see_aup']}${" "}${aup.value.version}${" "}<a href="<c:out value="${aup.value.link}"/>">${langProps['here']}</a></p> + </div> + </c:forEach> + <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> + <div class="form-group"> + <input type="submit" value="${langProps['agree_aup']}" class="btn btn-lg btn-primary btn-block"> + </div> + </form> +</div> +</div><!-- wrap --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/contact.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/contact.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/contact.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/contact.jsp diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/continue_direct.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/continue_direct.jsp new file mode 100644 index 000000000..1dd7fec9d --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/continue_direct.jsp @@ -0,0 +1,34 @@ +<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> + +<% + +List<String> cssLinks = new ArrayList<>(); + +pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${langProps['continue_direct_title']}" reqURL="${reqURL}" baseURL="${baseURL}" + cssLinks="${cssLinks}" theme="${theme}"/> + +<h1>${langProps['continue_direct_header']}</h1> + +</div> <%-- header --%> + +<div id="content"> + <div id="head"> + <h1>${langProps['continue_direct_heading']}</h1> + </div> + <p>${langProps['continue_direct_text']}</p> + <hr/> + <br/> + <a href="${fn:escapeXml(target)} "class="btn btn-lg btn-primary btn-block">${langProps['continue_direct_btn']}</a> +</div> +</div><!-- wrap --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/deviceApproved.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/deviceApproved.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/deviceApproved.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/deviceApproved.jsp diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/error.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/error.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/error.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/error.jsp diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/home.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/home.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/home.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/home.jsp diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/isTestSpWarning.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/isTestSpWarning.jsp new file mode 100644 index 000000000..3322c47a7 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/isTestSpWarning.jsp @@ -0,0 +1,39 @@ +<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common"%> + + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> + +<% + List<String> cssLinks = new ArrayList<>(); + pageContext.setAttribute("cssLinks", cssLinks); +%> + +<t:header title="${langProps['is_test_sp_warning_title']}" reqURL="${reqURL}" + baseURL="${baseURL}" cssLinks="${cssLinks}" theme="${theme}"/> + +</div> <%-- header --%> + +<div id="content"> + <div id="head"> + <h1>${langProps['is_test_sp_warning_header']}</h1> + </div> + <p>${langProps['is_test_sp_warning_text']}</p> + + <form method="GET" action="${action}"> + <hr/> + <br/> + <input type="hidden" name="target" value="${fn:escapeXml(target)}"> + <input type="hidden" name="accepted" value="true"> + <input type="submit" name="continue" value="${langProps['is_test_sp_warning_continue']}" + class="btn btn-lg btn-primary btn-block"> + </form> +</div> +</div><!-- ENDWRAP --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/login.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/login.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/login.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/login.jsp diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/login_failure.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/login_failure.jsp new file mode 100644 index 000000000..035ae11ae --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/login_failure.jsp @@ -0,0 +1,31 @@ +<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common"%> + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> +<% + +List<String> cssLinks = new ArrayList<>(); +pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${langProps['login_failure_title']}" reqURL="${reqURL}" baseURL="${baseURL}" + cssLinks="${cssLinks}" theme="${theme}"/> + +</div> <%-- header --%> + +<div id="content"> + <div id="head"> + <h1>${fn:escapeXml(langProps['login_failure_header'])}</h1> + </div> + <div class="msg">${langProps['login_failure_msg']}</div> + <div class="msg">${langProps['login_failure_contact_us']}<a href="mailto:${contactMail}">${contactMail}</a>.</div> +</div> +</div><!-- ENDWRAP --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/login_success.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/login_success.jsp new file mode 100644 index 000000000..c6da0c4a0 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/login_success.jsp @@ -0,0 +1,30 @@ +<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common"%> + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> +<% + +List<String> cssLinks = new ArrayList<>(); +pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${langProps['login_success_title']}" reqURL="${reqURL}" baseURL="${baseURL}" + cssLinks="${cssLinks}" theme="${theme}"/> + +</div> <%-- header --%> + +<div id="content"> + <div id="head"> + <h1>${fn:escapeXml(langProps['login_success_header'])}</h1> + </div> + <div class="msg">${langProps['login_success_msg']}</div> +</div> +</div><!-- ENDWRAP --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/logout.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/logout.jsp new file mode 100644 index 000000000..0d678f6d1 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/logout.jsp @@ -0,0 +1,42 @@ +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> + +<% + + List<String> cssLinks = new ArrayList<>(); + pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="Logout" reqURL="${reqURL}" baseURL="${baseURL}" cssLinks="${cssLinks}" theme="${theme}"/> + +<h1>${langProps['logout.confirmation.header']}</h1> +</div> <%-- header --%> + +<div id="content"> + <form action="${config.issuer}${config.issuer.endsWith('/') ? '' : '/'}endsession" method="POST"> + <p>${langProps["logout.confirmation.explanation"]}</p> + <div class="row"> + <div class="col-md-6 mb-4"> + <input name="approve" value="${langProps["logout.confirmation.submit"]}" + type="submit" class="btn btn-lg btn-block btn-primary" /> + </div> + <div class="col-md-6 mb-4"> + <input name="deny" value="${langProps["logout.confirmation.deny"]}" + type="submit" class="btn btn-lg btn-block" /> + </div> + </div> + <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> + </form> +</div> + +</div><!-- wrap --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/logoutConfirmation.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/logoutConfirmation.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/logoutConfirmation.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/logoutConfirmation.jsp diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/logout_denied.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/logout_denied.jsp new file mode 100644 index 000000000..f9886bd86 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/logout_denied.jsp @@ -0,0 +1,30 @@ +<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common"%> + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> +<% + +List<String> cssLinks = new ArrayList<>(); +pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${langProps['logout_denied_title']}" reqURL="${reqURL}" baseURL="${baseURL}" + cssLinks="${cssLinks}" theme="${theme}"/> + +</div> <%-- header --%> + +<div id="content"> + <div id="head"> + <h1>${fn:escapeXml(langProps['logout_denied_header'])}</h1> + </div> + <div class="msg">${langProps['logout_denied_msg']}</div> +</div> +</div><!-- ENDWRAP --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/logout_success.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/logout_success.jsp new file mode 100644 index 000000000..aaed2b8aa --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/logout_success.jsp @@ -0,0 +1,30 @@ +<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common"%> + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> +<% + +List<String> cssLinks = new ArrayList<>(); +pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${langProps['logout_success_title']}" reqURL="${reqURL}" baseURL="${baseURL}" + cssLinks="${cssLinks}" theme="${theme}"/> + +</div> <%-- header --%> + +<div id="content"> + <div id="head"> + <h1>${fn:escapeXml(langProps['logout_success_header'])}</h1> + </div> + <div class="msg">${langProps['logout_success_msg']}</div> +</div> +</div><!-- ENDWRAP --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/manage.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/manage.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/manage.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/manage.jsp diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/postLogout.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/postLogout.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/postLogout.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/postLogout.jsp diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/registrationForm.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/registrationForm.jsp new file mode 100644 index 000000000..fb8af4cd3 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/registrationForm.jsp @@ -0,0 +1,71 @@ +<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common"%> + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> +<% + +String samlCssUrl = (String) pageContext.getAttribute("samlResourcesURL"); +List<String> cssLinks = new ArrayList<>(); + +cssLinks.add(samlCssUrl + "/module.php/perun/res/css/perun_identity_choose_vo_and_group.css"); + +pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${langProps['registration_title']}" reqURL="${reqURL}" baseURL="${baseURL}" cssLinks="${cssLinks}" theme="${theme}"/> + +</div> <%-- header --%> + +<div id="content"> + <div id="head"> + <h1>${fn:escapeXml(langProps['registration_header1'])} + <c:choose> + <c:when test="${not empty client.clientName and not empty client.clientUri}"> +  <a href="${fn:escapeXml(client.clientUri)}">${fn:escapeXml(client.clientName)}</a> + </c:when> + <c:when test="${not empty client.clientName}"> +  ${fn:escapeXml(client.clientName)} + </c:when> + </c:choose> +  ${langProps['registration_header2']} + </h1> + </div> + <div class="msg">${langProps['registration_message']}</div> + + <div class="list-group"> + <form action="${action}" method="get"> + <h4>${langProps['registration_select_vo']}</h4> + <select id="selectVo" class="form-control" name="selectedVo" onchange="filter()" required> + <c:forEach var="voGroupPair" items="${groupsForRegistration}"> + <option value="${fn:escapeXml(voGroupPair.key.shortName)}"> + ${fn:escapeXml(voGroupPair.key.name)} + </option> + </c:forEach> + </select> + + <h4 class="selectGroup" style="display: none">${langProps['registration_select_group']}</h4> + <select class="selectGroup form-control" name="selectedGroup" class="form-control" style="display: none" required> + <c:forEach var="voGroupPair" items="${groupsForRegistration}"> + <c:forEach var="group" items="${voGroupPair.value}"> + <option class="groupOption" value="${fn:escapeXml(voGroupPair.key.shortName)}:${fn:escapeXml(group.name)}"> + ${fn:escapeXml(group.description)} + </option> + </c:forEach> + </c:forEach> + </select> + + <input type="submit" value="${langProps['registration_continue']}" class="btn btn-lg btn-primary btn-block"> + </form> + </div> +</div> +</div><!-- ENDWRAP --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> + +<script type="text/javascript" src="resources/js/reg_form_select.js"></script> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/registrationFormContinue.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/registrationFormContinue.jsp new file mode 100644 index 000000000..a8bf430b9 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/registrationFormContinue.jsp @@ -0,0 +1,51 @@ +<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common"%> + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> +<% + +String samlCssUrl = (String) pageContext.getAttribute("samlResourcesURL"); +List<String> cssLinks = new ArrayList<>(); + +cssLinks.add(samlCssUrl + "/module.php/perun/res/css/perun_identity_go_to_registration.css"); + +pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${langProps['go_to_registration_title']}" reqURL="${reqURL}" baseURL="${baseURL}" cssLinks="${cssLinks}" theme="${theme}"/> + +</div> <%-- header --%> + +<div id="content"> + <div id="head"> + <h1>${langProps['go_to_registration_header1']} + <c:choose> + <c:when test="${not empty client.clientName and not empty client.clientUri}"> +  <a href="${fn:escapeXml(client.uri)}">${fn:escapeXml(client.clientName)}</a> + </c:when> + <c:when test="${not empty client.clientName}"> +  ${fn:escapeXml(client.clientName)} + </c:when> + </c:choose> +  ${langProps['go_to_registration_header2']} + </h1> + </div> + <form method="GET" action="${action}"> + <hr/> + <br/> + <input type="hidden" name="client_id" value="${fn:escapeXml(client_id)}" /> + <input type="hidden" name="facility_id" value="${fn:escapeXml(facility_id)}" /> + <input type="hidden" name="user_id" value="${fn:escapeXml(user_id)}" /> + <input type="submit" name="continueToRegistration" value="${langProps['go_to_registration_continue']}" + class="btn btn-lg btn-primary btn-block"> + </form> +</div> +</div><!-- ENDWRAP --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/requestUserCode.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/requestUserCode.jsp similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/views/requestUserCode.jsp rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/requestUserCode.jsp diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedApprove.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedApprove.jsp new file mode 100644 index 000000000..f65506dca --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedApprove.jsp @@ -0,0 +1,54 @@ +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> +<% + + String samlCssUrl = (String) pageContext.getAttribute("samlResourcesURL"); + List<String> cssLinks = new ArrayList<>(); + + cssLinks.add(samlCssUrl + "/module.php/consent/assets/css/consent.css"); + cssLinks.add(samlCssUrl + "/module.php/perun/res/css/consent.css"); + + pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${langProps['consent_title']}" reqURL="${reqURL}" baseURL="${baseURL}" cssLinks="${cssLinks}" theme="${theme}"/> + +<h1 class="h3">${langProps['consent_header']} ${" "} ${fn:escapeXml(client.clientName)}</h1> + +</div> <%-- header --%> + +<div id="content"> + <c:remove scope="session" var="SPRING_SECURITY_LAST_EXCEPTION" /> + <form name="confirmationForm" + action="${pageContext.request.contextPath.endsWith('/') ? pageContext.request.contextPath : pageContext.request.contextPath.concat('/')}authorize" method="post"> + <p> + <c:if test="${not empty client.policyUri}"> + ${langProps['consent_privacy_policy']} +  <a target='_blank' href='${fn:escapeXml(client.policyUri)}'><em>${fn:escapeXml(client.clientName)}</em></a> + </c:if> + </p> + <t:attributesConsent /> + <div class="row" id="saveconsentcontainer"> + <div class="col-xs-12"> + <div class="checkbox"> + <input type="checkbox" name="remember" id="saveconsent" value="until-revoked"/> + <label for="saveconsent">${langProps['remember']}</label> + </div> + </div> + </div> + <input id="user_oauth_approval" name="user_oauth_approval" value="true" type="hidden" /> + <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> + <t:consentButtons /> + </form> +</div> +</div><!-- wrap --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedApproveDevice.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedApproveDevice.jsp new file mode 100644 index 000000000..9c78e5cc9 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedApproveDevice.jsp @@ -0,0 +1,50 @@ +<%@ page import="cz.muni.ics.oidc.server.elixir.GA4GHClaimSource" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> + +<% + + String samlCssUrl = (String) pageContext.getAttribute("samlResourcesURL"); + List<String> cssLinks = new ArrayList<>(); + + cssLinks.add(samlCssUrl + "/module.php/consent/assets/css/consent.css"); + cssLinks.add(samlCssUrl + "/module.php/perun/res/css/consent.css"); + + pageContext.setAttribute("cssLinks", cssLinks); + +%> + + <t:header title="${langProps['device_approve_title']}" reqURL="${reqURL}" baseURL="${baseURL}" + cssLinks="${cssLinks}" theme="${theme}"/> + + <h1 class="h3">${langProps['device_approve_header']} ${" "} ${fn:escapeXml(client.clientName)}</h1> + +</div> <%-- header --%> + +<div id="content"> + <c:remove scope="session" var="SPRING_SECURITY_LAST_EXCEPTION" /> + <form name="confirmationForm" + action="${ config.issuer }${ config.issuer.endsWith('/') ? '' : '/' }device/approve" method="post"> + <p> + <c:if test="${not empty client.policyUri}"> + ${langProps['device_approve_privacy']} +  <a target='_blank' href='${fn:escapeXml(client.policyUri)}'><em>${fn:escapeXml(client.clientName)}</em></a> + </c:if> + </p> + <t:attributesConsent/> + <input id="user_oauth_approval" name="user_oauth_approval" value="true" type="hidden" /> + <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> + <input type="hidden" name="user_code" value="${ dc.userCode }" /> + <t:consentButtons/> + </form> + </div> +</div><!-- wrap --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedDeviceApproved.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedDeviceApproved.jsp new file mode 100644 index 000000000..111be0a7d --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedDeviceApproved.jsp @@ -0,0 +1,45 @@ +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> + +<% + +List<String> cssLinks = new ArrayList<>(); +pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${langProps['device_approved_title']}" reqURL="${reqURL}" baseURL="${baseURL}" cssLinks="${cssLinks}" theme="${theme}"/> + +</div> <%-- header --%> + +<div id="content" class="text-center"> + <h1> + <c:if test="${ approved }"><p>✔ ${langProps['device_approved_approved']}</p></c:if> + <c:if test="${ not approved }"><p>✗ ${langProps['device_approved_rejected']}</p></c:if> + </h1> + <p class="mt-2"> + <c:if test="${ approved }"> + ${langProps['device_approved_text_approved_start']}${" "} + <c:if test="${empty client.clientName}"><em><c:out value="${client.clientId}" /></em></c:if> + <c:if test="${not empty client.clientName}"><em><c:out value="${client.clientName}" /></em></c:if> + ${" "}${langProps['device_approved_text_approved_end']} + </c:if> + <c:if test="${not approved}"> + ${langProps['device_approved_text_rejected_start']}${" "} + <c:if test="${empty client.clientName}"><em><c:out value="${client.clientId}" /></em></c:if> + <c:if test="${not empty client.clientName}"><em><c:out value="${client.clientName}" /></em></c:if> + ${". "}${langProps['device_approved_text_rejected_end']} + </c:if> + </p> +</div> + +</div> <%-- wrap --%> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedRequestUserCode.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedRequestUserCode.jsp new file mode 100644 index 000000000..bc60de450 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/themedRequestUserCode.jsp @@ -0,0 +1,69 @@ +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> + +<c:set var="baseURL" value="${baseURL}"/> +<c:set var="samlResourcesURL" value="${samlResourcesURL}"/> + +<% + + List<String> cssLinks = new ArrayList<>(); + pageContext.setAttribute("cssLinks", cssLinks); + +%> + + <t:header title="${langProps['request_code_title']}" reqURL="${reqURL}" baseURL="${baseURL}" + cssLinks="${cssLinks}" theme="${theme}"/> + +</div> <%-- header --%> + +<div id="content" class="text-center"> + <h1>${langProps['request_code_header']}</h1> + <c:choose> + <c:when test="${ not empty error }"> + <p class="alert alert-danger mt-2"> + <c:choose> + <c:when test="${ error == 'noUserCode' }">${langProps['user_code_empty_or_not_found']}</c:when> + <c:when test="${ error == 'expiredUserCode' }">${langProps['user_code_expired']}</c:when> + <c:when test="${ error == 'userCodeAlreadyApproved' }">${langProps['user_code_already_approved']}</c:when> + <c:when test="${ error == 'userCodeMismatch' }">${langProps['user_code_mismatch']}</c:when> + <c:otherwise>${langProps['user_code_error']}</c:otherwise> + </c:choose> + </p> + </c:when> + <c:otherwise> + <p class="mt-2"> + ${langProps['user_code_info']} + </p> + </c:otherwise> + </c:choose> + + <form name="confirmationForm" class="mt-2" + action="${ config.issuer }${ config.issuer.endsWith('/') ? '' : '/' }device/verify" method="post"> + <div class="row-fluid"> + <div class="span12"> + <div> + <div class="input-block-level input-xlarge"> + <input type="text" name="user_code" placeholder="${langProps['code']}" + autocorrect="off" autocapitalize="off" autocomplete="off" spellcheck="false" + value="" /> + </div> + </div> + </div> + </div> + <div class="row-fluid mt-2"> + <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> + <input type="hidden" name="acr" value="${acr}"> + <input name="approve" value="${langProps['user_code_submit']}" type="submit" + class="btn btn-success btn-block btn-large" /> + </div> + + </form> +</div> + +</div><!-- ENDWRAP --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> \ No newline at end of file diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/unapproved.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/unapproved.jsp new file mode 100644 index 000000000..49ffd8a08 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/unapproved.jsp @@ -0,0 +1,48 @@ +<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common"%> + +<% + +List<String> cssLinks = new ArrayList<>(); + +pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${title}" reqURL="${reqURL}" baseURL="${baseURL}" cssLinks="${cssLinks}" theme="${theme}"/> + +</div> <%-- header --%> + +<div id="content"> + <div class="error_message" style="word-wrap: break-word;"> + <c:forEach var="contactIter" items="${client.contacts}" end="0"> + <c:set var="contact" value="${contactIter}" /> + </c:forEach> + <c:if test="${empty contact}"> + <c:set var="contact" value="${contactMail}"/> + </c:if> + <h1>${langProps['403_header']}</h1> + <p>${langProps['403_text']} ${fn:escapeXml(client.clientName)} + <c:if test="${not empty client.clientUri}"> + <br/> + ${langProps['403_informationPage']}  + <a href="${fn:escapeXml(client.clientUri)}"> + ${fn:escapeXml(client.clientUri)} + </a> + </c:if> + </p> + + <p>${langProps['403_contactSupport']}  + <a href="mailto:${contact}?subject=${langProps["403_subject"]} ${fn:escapeXml(client.clientName)}"> + ${fn:escapeXml(contact)} + </a> + </p> + </div> +</div> +</div><!-- ENDWRAP --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/unapproved_spec.jsp b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/unapproved_spec.jsp new file mode 100644 index 000000000..6a2535752 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/views/unapproved_spec.jsp @@ -0,0 +1,29 @@ +<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true" %> +<%@ page import="java.util.ArrayList" %> +<%@ page import="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common"%> + +<% + +List<String> cssLinks = new ArrayList<>(); + +pageContext.setAttribute("cssLinks", cssLinks); + +%> + +<t:header title="${title}" reqURL="${reqURL}" baseURL="${baseURL}" cssLinks="${cssLinks}" theme="${theme}"/> + +</div> <%-- header --%> + +<div id="content"> + <div class="error_message" style="word-wrap: break-word;"> + <h1><c:out value="${outHeader}" escapeXml="false"/></h1> + <p><c:out value="${outMessage}" escapeXml="false"/></p> + <p>${langProps['contact_p']}${" "}<a href="mailto:${contactMail}">${contactMail}</a></p> + </div> +</div> +</div><!-- ENDWRAP --> + +<t:footer baseURL="${baseURL}" theme="${theme}"/> diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/web.xml b/perun-oidc-server-webapp/src/main/webapp/WEB-INF/web.xml similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/WEB-INF/web.xml rename to perun-oidc-server-webapp/src/main/webapp/WEB-INF/web.xml diff --git a/openid-connect-server-webapp/src/main/webapp/resources/bootstrap/img/glyphicons-halflings-white.png b/perun-oidc-server-webapp/src/main/webapp/resources/bootstrap/img/glyphicons-halflings-white.png similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/bootstrap/img/glyphicons-halflings-white.png rename to perun-oidc-server-webapp/src/main/webapp/resources/bootstrap/img/glyphicons-halflings-white.png diff --git a/openid-connect-server-webapp/src/main/webapp/resources/bootstrap/img/glyphicons-halflings.png b/perun-oidc-server-webapp/src/main/webapp/resources/bootstrap/img/glyphicons-halflings.png similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/bootstrap/img/glyphicons-halflings.png rename to perun-oidc-server-webapp/src/main/webapp/resources/bootstrap/img/glyphicons-halflings.png diff --git a/openid-connect-server-webapp/src/main/webapp/resources/bootstrap/js/bootstrap.js b/perun-oidc-server-webapp/src/main/webapp/resources/bootstrap/js/bootstrap.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/bootstrap/js/bootstrap.js rename to perun-oidc-server-webapp/src/main/webapp/resources/bootstrap/js/bootstrap.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/bootstrap/js/bootstrap.min.js b/perun-oidc-server-webapp/src/main/webapp/resources/bootstrap/js/bootstrap.min.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/bootstrap/js/bootstrap.min.js rename to perun-oidc-server-webapp/src/main/webapp/resources/bootstrap/js/bootstrap.min.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/css/bootstrap-responsive.min.css b/perun-oidc-server-webapp/src/main/webapp/resources/css/bootstrap-responsive.min.css similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/css/bootstrap-responsive.min.css rename to perun-oidc-server-webapp/src/main/webapp/resources/css/bootstrap-responsive.min.css diff --git a/openid-connect-server-webapp/src/main/webapp/resources/css/bootstrap-sheet.css b/perun-oidc-server-webapp/src/main/webapp/resources/css/bootstrap-sheet.css similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/css/bootstrap-sheet.css rename to perun-oidc-server-webapp/src/main/webapp/resources/css/bootstrap-sheet.css diff --git a/openid-connect-server-webapp/src/main/webapp/resources/css/bootstrap.min.css b/perun-oidc-server-webapp/src/main/webapp/resources/css/bootstrap.min.css similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/css/bootstrap.min.css rename to perun-oidc-server-webapp/src/main/webapp/resources/css/bootstrap.min.css diff --git a/perun-oidc-server-webapp/src/main/webapp/resources/css/customs.css b/perun-oidc-server-webapp/src/main/webapp/resources/css/customs.css new file mode 100644 index 000000000..69684b74b --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/resources/css/customs.css @@ -0,0 +1,36 @@ +.mt-0 { + margin-top: 0 !important; +} +.mr-half { + margin-right: .5em !important; +} +.checkbox-wrapper { + float: left; +} +.h4 { + clear: inherit !important; +} +.h1, .h2, .h3, .h4, .h5, .h6 { + letter-spacing: normal; +} +.mb-0 { + margin-bottom: 0 !important; +} +.mb-4 { + margin-bottom: 1.5rem; +} +.mt-0 { + margin-top: 0 !important; +} +.oh { + overflow: hidden; +} +.mt-2 { + margin-top: 2% !important; +} +.cw { + color: #FAFAFA !important; +} +.hidden { + display: none; +} diff --git a/openid-connect-server-webapp/src/main/webapp/resources/css/mitreid-connect-local.css b/perun-oidc-server-webapp/src/main/webapp/resources/css/mitreid-connect-local.css similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/css/mitreid-connect-local.css rename to perun-oidc-server-webapp/src/main/webapp/resources/css/mitreid-connect-local.css diff --git a/openid-connect-server-webapp/src/main/webapp/resources/css/mitreid-connect-responsive-local.css b/perun-oidc-server-webapp/src/main/webapp/resources/css/mitreid-connect-responsive-local.css similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/css/mitreid-connect-responsive-local.css rename to perun-oidc-server-webapp/src/main/webapp/resources/css/mitreid-connect-responsive-local.css diff --git a/openid-connect-server-webapp/src/main/webapp/resources/css/mitreid-connect-responsive.css b/perun-oidc-server-webapp/src/main/webapp/resources/css/mitreid-connect-responsive.css similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/css/mitreid-connect-responsive.css rename to perun-oidc-server-webapp/src/main/webapp/resources/css/mitreid-connect-responsive.css diff --git a/openid-connect-server-webapp/src/main/webapp/resources/css/mitreid-connect.css b/perun-oidc-server-webapp/src/main/webapp/resources/css/mitreid-connect.css similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/css/mitreid-connect.css rename to perun-oidc-server-webapp/src/main/webapp/resources/css/mitreid-connect.css diff --git a/perun-oidc-server-webapp/src/main/webapp/resources/images/arrow.png b/perun-oidc-server-webapp/src/main/webapp/resources/images/arrow.png new file mode 100644 index 000000000..ce608b467 Binary files /dev/null and b/perun-oidc-server-webapp/src/main/webapp/resources/images/arrow.png differ diff --git a/openid-connect-server-webapp/src/main/webapp/resources/images/heart_mode.png b/perun-oidc-server-webapp/src/main/webapp/resources/images/heart_mode.png similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/images/heart_mode.png rename to perun-oidc-server-webapp/src/main/webapp/resources/images/heart_mode.png diff --git a/openid-connect-server-webapp/src/main/webapp/resources/images/logo_placeholder.gif b/perun-oidc-server-webapp/src/main/webapp/resources/images/logo_placeholder.gif similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/images/logo_placeholder.gif rename to perun-oidc-server-webapp/src/main/webapp/resources/images/logo_placeholder.gif diff --git a/openid-connect-server-webapp/src/main/webapp/resources/images/mitreid-connect.ico b/perun-oidc-server-webapp/src/main/webapp/resources/images/mitreid-connect.ico similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/images/mitreid-connect.ico rename to perun-oidc-server-webapp/src/main/webapp/resources/images/mitreid-connect.ico diff --git a/openid-connect-server-webapp/src/main/webapp/resources/images/openid_connect_large.png b/perun-oidc-server-webapp/src/main/webapp/resources/images/openid_connect_large.png similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/images/openid_connect_large.png rename to perun-oidc-server-webapp/src/main/webapp/resources/images/openid_connect_large.png diff --git a/openid-connect-server-webapp/src/main/webapp/resources/images/openid_connect_small.png b/perun-oidc-server-webapp/src/main/webapp/resources/images/openid_connect_small.png similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/images/openid_connect_small.png rename to perun-oidc-server-webapp/src/main/webapp/resources/images/openid_connect_small.png diff --git a/perun-oidc-server-webapp/src/main/webapp/resources/images/perun_24px.png b/perun-oidc-server-webapp/src/main/webapp/resources/images/perun_24px.png new file mode 100644 index 000000000..c0134b936 Binary files /dev/null and b/perun-oidc-server-webapp/src/main/webapp/resources/images/perun_24px.png differ diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/admin.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/admin.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/admin.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/admin.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/blacklist.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/blacklist.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/blacklist.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/blacklist.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/client.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/client.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/client.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/client.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/dynreg.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/dynreg.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/dynreg.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/dynreg.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/grant.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/grant.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/grant.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/grant.js diff --git a/perun-oidc-server-webapp/src/main/webapp/resources/js/jquery-3-3-1.min.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/jquery-3-3-1.min.js new file mode 100644 index 000000000..4d9b3a258 --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/resources/js/jquery-3-3-1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:n.sort,splice:n.splice},w.extend=w.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||g(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)n=a[t],a!==(r=e[t])&&(l&&r&&(w.isPlainObject(r)||(i=Array.isArray(r)))?(i?(i=!1,o=n&&Array.isArray(n)?n:[]):o=n&&w.isPlainObject(n)?n:{},a[t]=w.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},w.extend({expando:"jQuery"+("3.3.1"+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==c.call(e))&&(!(t=i(e))||"function"==typeof(n=f.call(t,"constructor")&&t.constructor)&&p.call(n)===d)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e){m(e)},each:function(e,t){var n,r=0;if(C(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(C(Object(e))?w.merge(n,"string"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:u.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r,i=[],o=0,a=e.length,s=!n;o<a;o++)(r=!t(e[o],o))!==s&&i.push(e[o]);return i},map:function(e,t,n){var r,i,o=0,s=[];if(C(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&s.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&s.push(i);return a.apply([],s)},guid:1,support:h}),"function"==typeof Symbol&&(w.fn[Symbol.iterator]=n[Symbol.iterator]),w.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function C(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!g(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},P="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",I="\\["+M+"*("+R+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+R+"))|)"+M+"*\\]",W=":("+R+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+I+")*)|.*)\\)|)",$=new RegExp(M+"+","g"),B=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),F=new RegExp("^"+M+"*,"+M+"*"),_=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="<a id='"+b+"'></a><select id='"+b+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:he(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:he(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=r.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})r.pseudos[t]=fe(t);for(t in{submit:!0,reset:!0})r.pseudos[t]=pe(t);function ye(){}ye.prototype=r.filters=r.pseudos,r.setFilters=new ye,a=oe.tokenize=function(e,t){var n,i,o,a,s,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=r.preFilter;while(s){n&&!(i=F.exec(s))||(i&&(s=s.slice(i[0].length)||s),u.push(o=[])),n=!1,(i=_.exec(s))&&(n=i.shift(),o.push({value:n,type:i[0].replace(B," ")}),s=s.slice(n.length));for(a in r.filter)!(i=V[a].exec(s))||l[a]&&!(i=l[a](i))||(n=i.shift(),o.push({value:n,type:a,matches:i}),s=s.slice(n.length));if(!n)break}return t?s.length:s?oe.error(e):k(e,u).slice(0)};function ve(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function me(e,t,n){var r=t.dir,i=t.next,o=i||r,a=n&&"parentNode"===o,s=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||a)return e(t,n,i);return!1}:function(t,n,u){var l,c,f,p=[T,s];if(u){while(t=t[r])if((1===t.nodeType||a)&&e(t,n,u))return!0}else while(t=t[r])if(1===t.nodeType||a)if(f=t[b]||(t[b]={}),c=f[t.uniqueID]||(f[t.uniqueID]={}),i&&i===t.nodeName.toLowerCase())t=t[r]||t;else{if((l=c[o])&&l[0]===T&&l[1]===s)return p[2]=l[2];if(c[o]=p,p[2]=e(t,n,u))return!0}return!1}}function xe(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r<i;r++)oe(e,t[r],n);return n}function we(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Te(e,t,n,r,i,o){return r&&!r[b]&&(r=Te(r)),i&&!i[b]&&(i=Te(i,o)),se(function(o,a,s,u){var l,c,f,p=[],d=[],h=a.length,g=o||be(t||"*",s.nodeType?[s]:s,[]),y=!e||!o&&t?g:we(g,p,e,s,u),v=n?i||(o?e:h||r)?[]:a:y;if(n&&n(y,v,s,u),r){l=we(v,d),r(l,[],s,u),c=l.length;while(c--)(f=l[c])&&(v[d[c]]=!(y[d[c]]=f))}if(o){if(i||e){if(i){l=[],c=v.length;while(c--)(f=v[c])&&l.push(y[c]=f);i(null,v=[],l,u)}c=v.length;while(c--)(f=v[c])&&(l=i?O(o,f):p[c])>-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u<o;u++)if(n=r.relative[e[u].type])p=[me(xe(p),n)];else{if((n=r.filter[e[u].type].apply(null,e[u].matches))[b]){for(i=++u;i<o;i++)if(r.relative[e[i].type])break;return Te(u>1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u<i&&Ce(e.slice(u,i)),i<o&&Ce(e=e.slice(i)),i<o&&ve(e))}p.push(n)}return xe(p)}function Ee(e,t){var n=t.length>0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t<r;t++)if(w.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)w.find(e,i[t],n);return r>1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(w.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&w(e);if(!D.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?a.index(n)>-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s<o.length)!1===o[s].apply(n[0],n[1])&&e.stopOnFalse&&(s=o.length,n=!1)}e.memory||(n=!1),t=!1,i&&(o=n?[]:"")},l={add:function(){return o&&(n&&!t&&(s=o.length-1,a.push(n)),function t(n){w.each(n,function(n,r){g(r)?e.unique&&l.has(r)||o.push(r):r&&r.length&&"string"!==x(r)&&t(r)})}(arguments),n&&!t&&u()),this},remove:function(){return w.each(arguments,function(e,t){var n;while((n=w.inArray(t,o,n))>-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t<o)){if((e=r.apply(s,u))===n.promise())throw new TypeError("Thenable self-resolution");l=e&&("object"==typeof e||"function"==typeof e)&&e.then,g(l)?i?l.call(e,a(o,n,I,i),a(o,n,W,i)):(o++,l.call(e,a(o,n,I,i),a(o,n,W,i),a(o,n,I,n.notifyWith))):(r!==I&&(s=void 0,u=[e]),(i||n.resolveWith)(s,u))}},c=i?l:function(){try{l()}catch(e){w.Deferred.exceptionHook&&w.Deferred.exceptionHook(e,c.stackTrace),t+1>=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},X=/^-ms-/,U=/-([a-z])/g;function V(e,t){return t.toUpperCase()}function G(e){return e.replace(X,"ms-").replace(U,V)}var Y=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Q(){this.expando=w.expando+Q.uid++}Q.uid=1,Q.prototype={cache:function(e){var t=e[this.expando];return t||(t={},Y(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[G(t)]=n;else for(r in t)i[G(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][G(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(G):(t=G(t))in r?[t]:t.match(M)||[]).length;while(n--)delete r[t[n]]}(void 0===t||w.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!w.isEmptyObject(t)}};var J=new Q,K=new Q,Z=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,ee=/[A-Z]/g;function te(e){return"true"===e||"false"!==e&&("null"===e?null:e===+e+""?+e:Z.test(e)?JSON.parse(e):e)}function ne(e,t,n){var r;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(ee,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n=te(n)}catch(e){}K.set(e,t,n)}else n=void 0;return n}w.extend({hasData:function(e){return K.hasData(e)||J.hasData(e)},data:function(e,t,n){return K.access(e,t,n)},removeData:function(e,t){K.remove(e,t)},_data:function(e,t,n){return J.access(e,t,n)},_removeData:function(e,t){J.remove(e,t)}}),w.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=K.get(o),1===o.nodeType&&!J.get(o,"hasDataAttrs"))){n=a.length;while(n--)a[n]&&0===(r=a[n].name).indexOf("data-")&&(r=G(r.slice(5)),ne(o,r,i[r]));J.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof e?this.each(function(){K.set(this,e)}):z(this,function(t){var n;if(o&&void 0===t){if(void 0!==(n=K.get(o,e)))return n;if(void 0!==(n=ne(o,e)))return n}else this.each(function(){K.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length<n?w.queue(this[0],e):void 0===t?this:this.each(function(){var n=w.queue(this,e,t);w._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&w.dequeue(this,e)})},dequeue:function(e){return this.each(function(){w.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=w.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=J.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var re=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ie=new RegExp("^(?:([+-])=|)("+re+")([a-z%]*)$","i"),oe=["Top","Right","Bottom","Left"],ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&w.contains(e.ownerDocument,e)&&"none"===w.css(e,"display")},se=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i};function ue(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return w.css(e,t,"")},u=s(),l=n&&n[3]||(w.cssNumber[t]?"":"px"),c=(w.cssNumber[t]||"px"!==l&&+u)&&ie.exec(w.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)w.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,w.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var le={};function ce(e){var t,n=e.ownerDocument,r=e.nodeName,i=le[r];return i||(t=n.body.appendChild(n.createElement(r)),i=w.css(t,"display"),t.parentNode.removeChild(t),"none"===i&&(i="block"),le[r]=i,i)}function fe(e,t){for(var n,r,i=[],o=0,a=e.length;o<a;o++)(r=e[o]).style&&(n=r.style.display,t?("none"===n&&(i[o]=J.get(r,"display")||null,i[o]||(r.style.display="")),""===r.style.display&&ae(r)&&(i[o]=ce(r))):"none"!==n&&(i[o]="none",J.set(r,"display",n)));for(o=0;o<a;o++)null!=i[o]&&(e[o].style.display=i[o]);return e}w.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?w(this).show():w(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n<r;n++)J.set(e[n],"globalEval",!t||J.get(t[n],"globalEval"))}var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===x(o))w.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+w.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;w.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&w.inArray(o,r)>-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="<textarea>x</textarea>",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n<arguments.length;n++)u[n]=arguments[n];if(t.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,t)){s=w.event.handlers.call(this,t,l),n=0;while((o=s[n++])&&!t.isPropagationStopped()){t.currentTarget=o.elem,r=0;while((a=o.handlers[r++])&&!t.isImmediatePropagationStopped())t.rnamespace&&!t.rnamespace.test(a.namespace)||(t.handleObj=a,t.data=a.data,void 0!==(i=((w.event.special[a.origType]||{}).handle||a.handler).apply(o.elem,u))&&!1===(t.result=i)&&(t.preventDefault(),t.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,t),t.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&e.button>=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?w(i,this).index(l)>-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(e,t){Object.defineProperty(w.Event.prototype,e,{enumerable:!0,configurable:!0,get:g(t)?function(){if(this.originalEvent)return t(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[e]},set:function(t){Object.defineProperty(this,e,{enumerable:!0,configurable:!0,writable:!0,value:t})}})},fix:function(e){return e[w.expando]?e:new w.Event(e)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==Se()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===Se()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&N(this,"input"))return this.click(),!1},_default:function(e){return N(e.target,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},w.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},w.Event=function(e,t){if(!(this instanceof w.Event))return new w.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ee:ke,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&w.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[w.expando]=!0},w.Event.prototype={constructor:w.Event,isDefaultPrevented:ke,isPropagationStopped:ke,isImmediatePropagationStopped:ke,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ee,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ee,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ee,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},w.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&we.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Te.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},w.event.addProp),w.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,t){w.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return i&&(i===r||w.contains(r,i))||(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),w.fn.extend({on:function(e,t,n,r){return De(this,e,t,n,r)},one:function(e,t,n,r){return De(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,w(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=ke),this.each(function(){w.event.remove(this,e,n,t)})}});var Ne=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/<script|<style|<link/i,je=/checked\s*(?:[^=]|=\s*.checked.)/i,qe=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n<r;n++)w.event.add(t,i,l[i][n])}K.hasData(e)&&(s=K.access(e),u=w.extend({},s),K.set(t,u))}}function Me(e,t){var n=t.nodeName.toLowerCase();"input"===n&&pe.test(e.type)?t.checked=e.checked:"input"!==n&&"textarea"!==n||(t.defaultValue=e.defaultValue)}function Re(e,t,n,r){t=a.apply([],t);var i,o,s,u,l,c,f=0,p=e.length,d=p-1,y=t[0],v=g(y);if(v||p>1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f<p;f++)l=i,f!==d&&(l=w.clone(l,!0,!0),u&&w.merge(s,ye(l,"script"))),n.call(e[f],l,f);if(u)for(c=s[s.length-1].ownerDocument,w.map(s,Oe),f=0;f<u;f++)l=s[f],he.test(l.type||"")&&!J.access(l,"globalEval")&&w.contains(c,l)&&(l.src&&"module"!==(l.type||"").toLowerCase()?w._evalUrl&&w._evalUrl(l.src):m(l.textContent.replace(qe,""),c,l))}return e}function Ie(e,t,n){for(var r,i=t?w.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||w.cleanData(ye(r)),r.parentNode&&(n&&w.contains(r.ownerDocument,r)&&ve(ye(r,"script")),r.parentNode.removeChild(r));return e}w.extend({htmlPrefilter:function(e){return e.replace(Ne,"<$1></$2>")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r<i;r++)Me(o[r],a[r]);if(t)if(n)for(o=o||ye(e),a=a||ye(s),r=0,i=o.length;r<i;r++)Pe(o[r],a[r]);else Pe(e,s);return(a=ye(s,"script")).length>0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(w.cleanData(ye(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=[];return Re(this,arguments,function(t){var n=this.parentNode;w.inArray(this,e)<0&&(w.cleanData(ye(this)),n&&n.replaceChild(t,this))},e)}}),w.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){w.fn[e]=function(e){for(var n,r=[],i=w(e),o=i.length-1,a=0;a<=o;a++)n=a===o?this:this.clone(!0),w(i[a])[t](n),s.apply(r,n.get());return this.pushStack(r)}});var We=new RegExp("^("+re+")(?!px)[a-z%]+$","i"),$e=function(t){var n=t.ownerDocument.defaultView;return n&&n.opener||(n=e),n.getComputedStyle(t)},Be=new RegExp(oe.join("|"),"i");!function(){function t(){if(c){l.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",c.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",be.appendChild(l).appendChild(c);var t=e.getComputedStyle(c);i="1%"!==t.top,u=12===n(t.marginLeft),c.style.right="60%",s=36===n(t.right),o=36===n(t.width),c.style.position="absolute",a=36===c.offsetWidth||"absolute",be.removeChild(l),c=null}}function n(e){return Math.round(parseFloat(e))}var i,o,a,s,u,l=r.createElement("div"),c=r.createElement("div");c.style&&(c.style.backgroundClip="content-box",c.cloneNode(!0).style.backgroundClip="",h.clearCloneStyle="content-box"===c.style.backgroundClip,w.extend(h,{boxSizingReliable:function(){return t(),o},pixelBoxStyles:function(){return t(),s},pixelPosition:function(){return t(),i},reliableMarginLeft:function(){return t(),u},scrollboxSize:function(){return t(),a}}))}();function Fe(e,t,n){var r,i,o,a,s=e.style;return(n=n||$e(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||w.contains(e.ownerDocument,e)||(a=w.style(e,t)),!h.pixelBoxStyles()&&We.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function _e(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}var ze=/^(none|table(?!-c[ea]).+)/,Xe=/^--/,Ue={position:"absolute",visibility:"hidden",display:"block"},Ve={letterSpacing:"0",fontWeight:"400"},Ge=["Webkit","Moz","ms"],Ye=r.createElement("div").style;function Qe(e){if(e in Ye)return e;var t=e[0].toUpperCase()+e.slice(1),n=Ge.length;while(n--)if((e=Ge[n]+t)in Ye)return e}function Je(e){var t=w.cssProps[e];return t||(t=w.cssProps[e]=Qe(e)||e),t}function Ke(e,t,n){var r=ie.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Ze(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=w.css(e,n+oe[a],!0,i)),r?("content"===n&&(u-=w.css(e,"padding"+oe[a],!0,i)),"margin"!==n&&(u-=w.css(e,"border"+oe[a]+"Width",!0,i))):(u+=w.css(e,"padding"+oe[a],!0,i),"padding"!==n?u+=w.css(e,"border"+oe[a]+"Width",!0,i):s+=w.css(e,"border"+oe[a]+"Width",!0,i));return!r&&o>=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a<i;a++)o[t[a]]=w.css(e,t[a],!1,r);return o}return void 0!==n?w.style(e,t,n):w.css(e,t)},e,t,arguments.length>1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function ct(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),y=J.get(e,"fxshow");n.queue||(null==(a=w._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,w.queue(e,"fx").length||a.empty.fire()})}));for(r in t)if(i=t[r],it.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!y||void 0===y[r])continue;g=!0}d[r]=y&&y[r]||w.style(e,r)}if((u=!w.isEmptyObject(t))||!w.isEmptyObject(d)){f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=y&&y.display)&&(l=J.get(e,"display")),"none"===(c=w.css(e,"display"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=w.css(e,"display"),fe([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===w.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1;for(r in d)u||(y?"hidden"in y&&(g=y.hidden):y=J.access(e,"fxshow",{display:l}),o&&(y.hidden=!g),g&&fe([e],!0),p.done(function(){g||fe([e]),J.remove(e,"fxshow");for(r in d)w.style(e,r,d[r])})),u=lt(g?y[r]:0,r,p),r in y||(y[r]=u.start,g&&(u.end=u.start,u.start=0))}}function ft(e,t){var n,r,i,o,a;for(n in e)if(r=G(n),i=t[r],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=w.cssHooks[r])&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}function pt(e,t,n){var r,i,o=0,a=pt.prefilters.length,s=w.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;for(var t=nt||st(),n=Math.max(0,l.startTime+l.duration-t),r=1-(n/l.duration||0),o=0,a=l.tweens.length;o<a;o++)l.tweens[o].run(r);return s.notifyWith(e,[l,r,n]),r<1&&a?n:(a||s.notifyWith(e,[l,1,0]),s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:w.extend({},t),opts:w.extend(!0,{specialEasing:{},easing:w.easing._default},n),originalProperties:t,originalOptions:n,startTime:nt||st(),duration:n.duration,tweens:[],createTween:function(t,n){var r=w.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;n<r;n++)l.tweens[n].run(1);return t?(s.notifyWith(e,[l,1,0]),s.resolveWith(e,[l,t])):s.rejectWith(e,[l,t]),this}}),c=l.props;for(ft(c,l.opts.specialEasing);o<a;o++)if(r=pt.prefilters[o].call(l,e,c,l.opts))return g(r.stop)&&(w._queueHooks(l.elem,l.opts.queue).stop=r.stop.bind(r)),r;return w.map(c,lt,l),g(l.opts.start)&&l.opts.start.call(e,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),w.fx.timer(w.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l}w.Animation=w.extend(pt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return ue(n.elem,e,ie.exec(t),n),n}]},tweener:function(e,t){g(e)?(t=e,e=["*"]):e=e.match(M);for(var n,r=0,i=e.length;r<i;r++)n=e[r],pt.tweeners[n]=pt.tweeners[n]||[],pt.tweeners[n].unshift(t)},prefilters:[ct],prefilter:function(e,t){t?pt.prefilters.unshift(e):pt.prefilters.push(e)}}),w.speed=function(e,t,n){var r=e&&"object"==typeof e?w.extend({},e):{complete:n||!n&&t||g(e)&&e,duration:e,easing:n&&t||t&&!g(t)&&t};return w.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in w.fx.speeds?r.duration=w.fx.speeds[r.duration]:r.duration=w.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){g(r.old)&&r.old.call(this),r.queue&&w.dequeue(this,r.queue)},r},w.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=w.isEmptyObject(e),o=w.speed(t,n,r),a=function(){var t=pt(this,w.extend({},e),o);(i||J.get(this,"finish"))&&t.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=void 0),t&&!1!==e&&this.queue(e||"fx",[]),this.each(function(){var t=!0,i=null!=e&&e+"queueHooks",o=w.timers,a=J.get(this);if(i)a[i]&&a[i].stop&&r(a[i]);else for(i in a)a[i]&&a[i].stop&&ot.test(i)&&r(a[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));!t&&n||w.dequeue(this,e)})},finish:function(e){return!1!==e&&(e=e||"fx"),this.each(function(){var t,n=J.get(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=w.timers,a=r?r.length:0;for(n.finish=!0,w.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;t<a;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}}),w.each(["toggle","show","hide"],function(e,t){var n=w.fn[t];w.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ut(t,!0),e,r,i)}}),w.each({slideDown:ut("show"),slideUp:ut("hide"),slideToggle:ut("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){w.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),w.timers=[],w.fx.tick=function(){var e,t=0,n=w.timers;for(nt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||w.fx.stop(),nt=void 0},w.fx.timer=function(e){w.timers.push(e),w.fx.start()},w.fx.interval=13,w.fx.start=function(){rt||(rt=!0,at())},w.fx.stop=function(){rt=null},w.fx.speeds={slow:600,fast:200,_default:400},w.fn.delay=function(t,n){return t=w.fx?w.fx.speeds[t]||t:t,n=n||"fx",this.queue(n,function(n,r){var i=e.setTimeout(n,t);r.stop=function(){e.clearTimeout(i)}})},function(){var e=r.createElement("input"),t=r.createElement("select").appendChild(r.createElement("option"));e.type="checkbox",h.checkOn=""!==e.value,h.optSelected=t.selected,(e=r.createElement("input")).value="t",e.type="radio",h.radioValue="t"===e.value}();var dt,ht=w.expr.attrHandle;w.fn.extend({attr:function(e,t){return z(this,w.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!N(n.parentNode,"optgroup"))){if(t=w(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=w.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=w.inArray(w.valHooks.option.get(r),o)>-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w("<script>").prop({charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&o("error"===e.type?404:200,e.type)}),r.head.appendChild(t[0])},abort:function(){n&&n()}}}});var Yt=[],Qt=/(=)\?(?=&|$)|\?\?/;w.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Yt.pop()||w.expando+"_"+Et++;return this[e]=!0,e}}),w.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,a,s=!1!==t.jsonp&&(Qt.test(t.url)?"url":"string"==typeof t.data&&0===(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&Qt.test(t.data)&&"data");if(s||"jsonp"===t.dataTypes[0])return i=t.jsonpCallback=g(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,s?t[s]=t[s].replace(Qt,"$1"+i):!1!==t.jsonp&&(t.url+=(kt.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return a||w.error(i+" was not called"),a[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){a=arguments},r.always(function(){void 0===o?w(e).removeProp(i):e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,Yt.push(i)),a&&g(o)&&o(a[0]),a=o=void 0}),"script"}),h.createHTMLDocument=function(){var e=r.implementation.createHTMLDocument("").body;return e.innerHTML="<form></form><form></form>",2===e.childNodes.length}(),w.parseHTML=function(e,t,n){if("string"!=typeof e)return[];"boolean"==typeof t&&(n=t,t=!1);var i,o,a;return t||(h.createHTMLDocument?((i=(t=r.implementation.createHTMLDocument("")).createElement("base")).href=r.location.href,t.head.appendChild(i)):t=r),o=A.exec(e),a=!n&&[],o?[t.createElement(o[1])]:(o=xe([e],t,a),a&&a.length&&w(a).remove(),w.merge([],o.childNodes))},w.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return s>-1&&(r=vt(e.slice(s)),e=e.slice(0,s)),g(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),a.length>0&&w.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?w("<div>").append(w.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},w.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){w.fn[t]=function(e){return this.on(t,e)}}),w.expr.pseudos.animated=function(e){return w.grep(w.timers,function(t){return e===t.elem}).length},w.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l,c=w.css(e,"position"),f=w(e),p={};"static"===c&&(e.style.position="relative"),s=f.offset(),o=w.css(e,"top"),u=w.css(e,"left"),(l=("absolute"===c||"fixed"===c)&&(o+u).indexOf("auto")>-1)?(a=(r=f.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),g(t)&&(t=t.call(e,n,w.extend({},s))),null!=t.top&&(p.top=t.top-s.top+a),null!=t.left&&(p.left=t.left-s.left+i),"using"in t?t.using.call(e,p):f.css(p)}},w.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){w.offset.setOffset(this,e,t)});var t,n,r=this[0];if(r)return r.getClientRects().length?(t=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:t.top+n.pageYOffset,left:t.left+n.pageXOffset}):{top:0,left:0}},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===w.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===w.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=w(e).offset()).top+=w.css(e,"borderTopWidth",!0),i.left+=w.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-w.css(r,"marginTop",!0),left:t.left-i.left-w.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===w.css(e,"position"))e=e.offsetParent;return e||be})}}),w.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,t){var n="pageYOffset"===t;w.fn[e]=function(r){return z(this,function(e,r,i){var o;if(y(e)?o=e:9===e.nodeType&&(o=e.defaultView),void 0===i)return o?o[t]:e[r];o?o.scrollTo(n?o.pageXOffset:i,n?i:o.pageYOffset):e[r]=i},e,r,arguments.length)}}),w.each(["top","left"],function(e,t){w.cssHooks[t]=_e(h.pixelPosition,function(e,n){if(n)return n=Fe(e,t),We.test(n)?w(e).position()[t]+"px":n})}),w.each({Height:"height",Width:"width"},function(e,t){w.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){w.fn[r]=function(i,o){var a=arguments.length&&(n||"boolean"!=typeof i),s=n||(!0===i||!0===o?"margin":"border");return z(this,function(t,n,i){var o;return y(t)?0===r.indexOf("outer")?t["inner"+e]:t.document.documentElement["client"+e]:9===t.nodeType?(o=t.documentElement,Math.max(t.body["scroll"+e],o["scroll"+e],t.body["offset"+e],o["offset"+e],o["client"+e])):void 0===i?w.css(t,n,s):w.style(t,n,i,s)},t,a?i:void 0,a)}})}),w.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,t){w.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),w.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),w.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),w.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),g(e))return r=o.call(arguments,2),i=function(){return e.apply(t||this,r.concat(o.call(arguments)))},i.guid=e.guid=e.guid||w.guid++,i},w.holdReady=function(e){e?w.readyWait++:w.ready(!0)},w.isArray=Array.isArray,w.parseJSON=JSON.parse,w.nodeName=N,w.isFunction=g,w.isWindow=y,w.camelCase=G,w.type=x,w.now=Date.now,w.isNumeric=function(e){var t=w.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},"function"==typeof define&&define.amd&&define("jquery",[],function(){return w});var Jt=e.jQuery,Kt=e.$;return w.noConflict=function(t){return e.$===w&&(e.$=Kt),t&&e.jQuery===w&&(e.jQuery=Jt),w},t||(e.jQuery=e.$=w),w}); diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/lib/backbone.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/lib/backbone.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/lib/backbone.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/lib/backbone.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/lib/backbone.validations.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/lib/backbone.validations.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/lib/backbone.validations.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/lib/backbone.validations.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/lib/bootpag.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/lib/bootpag.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/lib/bootpag.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/lib/bootpag.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/lib/bootstrap-sheet.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/lib/bootstrap-sheet.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/lib/bootstrap-sheet.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/lib/bootstrap-sheet.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/lib/bootstrapx-clickover.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/lib/bootstrapx-clickover.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/lib/bootstrapx-clickover.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/lib/bootstrapx-clickover.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/lib/html5.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/lib/html5.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/lib/html5.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/lib/html5.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/lib/i18next.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/lib/i18next.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/lib/i18next.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/lib/i18next.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/lib/jquery.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/lib/jquery.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/lib/jquery.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/lib/jquery.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/lib/moment-with-locales.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/lib/moment-with-locales.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/lib/moment-with-locales.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/lib/moment-with-locales.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/lib/purl.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/lib/purl.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/lib/purl.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/lib/purl.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/lib/underscore.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/lib/underscore.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/lib/underscore.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/lib/underscore.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/locale/en/messages.json b/perun-oidc-server-webapp/src/main/webapp/resources/js/locale/en/messages.json similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/locale/en/messages.json rename to perun-oidc-server-webapp/src/main/webapp/resources/js/locale/en/messages.json diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/locale/fr/messages.json b/perun-oidc-server-webapp/src/main/webapp/resources/js/locale/fr/messages.json similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/locale/fr/messages.json rename to perun-oidc-server-webapp/src/main/webapp/resources/js/locale/fr/messages.json diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/locale/sv/messages.json b/perun-oidc-server-webapp/src/main/webapp/resources/js/locale/sv/messages.json similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/locale/sv/messages.json rename to perun-oidc-server-webapp/src/main/webapp/resources/js/locale/sv/messages.json diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/locale/zh/messages.json b/perun-oidc-server-webapp/src/main/webapp/resources/js/locale/zh/messages.json similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/locale/zh/messages.json rename to perun-oidc-server-webapp/src/main/webapp/resources/js/locale/zh/messages.json diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/locale/zh_CN/messages.json b/perun-oidc-server-webapp/src/main/webapp/resources/js/locale/zh_CN/messages.json similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/locale/zh_CN/messages.json rename to perun-oidc-server-webapp/src/main/webapp/resources/js/locale/zh_CN/messages.json diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/locale/zh_TW/messages.json b/perun-oidc-server-webapp/src/main/webapp/resources/js/locale/zh_TW/messages.json similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/locale/zh_TW/messages.json rename to perun-oidc-server-webapp/src/main/webapp/resources/js/locale/zh_TW/messages.json diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/profile.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/profile.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/profile.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/profile.js diff --git a/perun-oidc-server-webapp/src/main/webapp/resources/js/reg_form_select.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/reg_form_select.js new file mode 100644 index 000000000..65fcc892b --- /dev/null +++ b/perun-oidc-server-webapp/src/main/webapp/resources/js/reg_form_select.js @@ -0,0 +1,25 @@ +function filter() { + hideGroups(); + $('.selectGroup').val(""); + const vo = $("#selectVo").val(); + if (vo !== "") { + showGroups(); + $(".groupOption").each(function () { + const value = $(this).val(); + if (value.startsWith(vo, 0)) { + $(this).show(); + } else { + $(this).hide(); + } + }); + } +} +function showGroups() { + $(".selectGroup").show(); +} +function hideGroups() { + $(".selectGroup").hide(); +} +$(document).ready(function() { + $("#selectVo").val(""); +}); diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/rsreg.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/rsreg.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/rsreg.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/rsreg.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/scope.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/scope.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/scope.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/scope.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/token.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/token.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/token.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/token.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/whitelist.js b/perun-oidc-server-webapp/src/main/webapp/resources/js/whitelist.js similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/js/whitelist.js rename to perun-oidc-server-webapp/src/main/webapp/resources/js/whitelist.js diff --git a/openid-connect-server-webapp/src/main/webapp/resources/template/admin.html b/perun-oidc-server-webapp/src/main/webapp/resources/template/admin.html similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/template/admin.html rename to perun-oidc-server-webapp/src/main/webapp/resources/template/admin.html diff --git a/openid-connect-server-webapp/src/main/webapp/resources/template/blacklist.html b/perun-oidc-server-webapp/src/main/webapp/resources/template/blacklist.html similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/template/blacklist.html rename to perun-oidc-server-webapp/src/main/webapp/resources/template/blacklist.html diff --git a/openid-connect-server-webapp/src/main/webapp/resources/template/client.html b/perun-oidc-server-webapp/src/main/webapp/resources/template/client.html similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/template/client.html rename to perun-oidc-server-webapp/src/main/webapp/resources/template/client.html diff --git a/openid-connect-server-webapp/src/main/webapp/resources/template/dynreg.html b/perun-oidc-server-webapp/src/main/webapp/resources/template/dynreg.html similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/template/dynreg.html rename to perun-oidc-server-webapp/src/main/webapp/resources/template/dynreg.html diff --git a/openid-connect-server-webapp/src/main/webapp/resources/template/grant.html b/perun-oidc-server-webapp/src/main/webapp/resources/template/grant.html similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/template/grant.html rename to perun-oidc-server-webapp/src/main/webapp/resources/template/grant.html diff --git a/openid-connect-server-webapp/src/main/webapp/resources/template/rsreg.html b/perun-oidc-server-webapp/src/main/webapp/resources/template/rsreg.html similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/template/rsreg.html rename to perun-oidc-server-webapp/src/main/webapp/resources/template/rsreg.html diff --git a/openid-connect-server-webapp/src/main/webapp/resources/template/scope.html b/perun-oidc-server-webapp/src/main/webapp/resources/template/scope.html similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/template/scope.html rename to perun-oidc-server-webapp/src/main/webapp/resources/template/scope.html diff --git a/openid-connect-server-webapp/src/main/webapp/resources/template/token.html b/perun-oidc-server-webapp/src/main/webapp/resources/template/token.html similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/template/token.html rename to perun-oidc-server-webapp/src/main/webapp/resources/template/token.html diff --git a/openid-connect-server-webapp/src/main/webapp/resources/template/whitelist.html b/perun-oidc-server-webapp/src/main/webapp/resources/template/whitelist.html similarity index 100% rename from openid-connect-server-webapp/src/main/webapp/resources/template/whitelist.html rename to perun-oidc-server-webapp/src/main/webapp/resources/template/whitelist.html diff --git a/openid-connect-server/.gitignore b/perun-oidc-server/.gitignore similarity index 100% rename from openid-connect-server/.gitignore rename to perun-oidc-server/.gitignore diff --git a/openid-connect-server/pom.xml b/perun-oidc-server/pom.xml similarity index 65% rename from openid-connect-server/pom.xml rename to perun-oidc-server/pom.xml index 716fb4d9d..60d49d5a0 100644 --- a/openid-connect-server/pom.xml +++ b/perun-oidc-server/pom.xml @@ -18,23 +18,15 @@ --> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> - <artifactId>openid-connect-server</artifactId> - <name>OpenID Connect Server Library</name> + <parent> - <groupId>org.mitre</groupId> - <artifactId>openid-connect-parent</artifactId> + <groupId>cz.muni.ics</groupId> + <artifactId>perun-oidc-parent</artifactId> <version>2.0.0</version> <relativePath>../pom.xml</relativePath> </parent> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - </plugin> - </plugins> - </build> + <artifactId>perun-oidc-server</artifactId> <dependencies> <dependency> @@ -73,10 +65,6 @@ <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> </dependency> - <dependency> - <groupId>ch.qos.logback</groupId> - <artifactId>logback-classic</artifactId> - </dependency> <dependency> <groupId>com.nimbusds</groupId> <artifactId>nimbus-jose-jwt</artifactId> @@ -97,10 +85,6 @@ <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> - <dependency> - <groupId>javax.servlet</groupId> - <artifactId>servlet-api</artifactId> - </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> @@ -127,8 +111,89 @@ <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>jstl</artifactId> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.dataformat</groupId> + <artifactId>jackson-dataformat-yaml</artifactId> + </dependency> + <dependency> + <groupId>org.mariadb.jdbc</groupId> + <artifactId>mariadb-java-client</artifactId> + </dependency> + <dependency> + <groupId>org.apache.directory.api</groupId> + <artifactId>api-all</artifactId> + </dependency> + <dependency> + <groupId>org.codehaus.janino</groupId> + <artifactId>janino</artifactId> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jul-to-slf4j</artifactId> + </dependency> + <dependency> + <groupId>net.javacrumbs.shedlock</groupId> + <artifactId>shedlock-spring</artifactId> + </dependency> + <dependency> + <groupId>net.javacrumbs.shedlock</groupId> + <artifactId>shedlock-provider-jdbc-template</artifactId> + </dependency> + <dependency> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jaxb</groupId> + <artifactId>jaxb-runtime</artifactId> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-aop</artifactId> + </dependency> + <dependency> + <groupId>org.aspectj</groupId> + <artifactId>aspectjweaver</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.security.extensions</groupId> + <artifactId>spring-security-saml2-core</artifactId> + </dependency> </dependencies> - <description>OpenID Connect server libraries for Spring and Spring Security.</description> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + </plugin> + </plugins> + </build> </project> diff --git a/openid-connect-server/src/main/java/org/mitre/data/AbstractPageOperationTemplate.java b/perun-oidc-server/src/main/java/cz/muni/ics/data/AbstractPageOperationTemplate.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/data/AbstractPageOperationTemplate.java rename to perun-oidc-server/src/main/java/cz/muni/ics/data/AbstractPageOperationTemplate.java index 54a35d952..9e6cb30ed 100644 --- a/openid-connect-server/src/main/java/org/mitre/data/AbstractPageOperationTemplate.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/data/AbstractPageOperationTemplate.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.data; +package cz.muni.ics.data; import java.util.Collection; import java.util.HashSet; diff --git a/openid-connect-server/src/main/java/org/mitre/data/DefaultPageCriteria.java b/perun-oidc-server/src/main/java/cz/muni/ics/data/DefaultPageCriteria.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/data/DefaultPageCriteria.java rename to perun-oidc-server/src/main/java/cz/muni/ics/data/DefaultPageCriteria.java index 050f489ac..8efeb8e73 100644 --- a/openid-connect-server/src/main/java/org/mitre/data/DefaultPageCriteria.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/data/DefaultPageCriteria.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.data; +package cz.muni.ics.data; /** * Default implementation of PageCriteria which specifies diff --git a/openid-connect-server/src/main/java/org/mitre/data/PageCriteria.java b/perun-oidc-server/src/main/java/cz/muni/ics/data/PageCriteria.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/data/PageCriteria.java rename to perun-oidc-server/src/main/java/cz/muni/ics/data/PageCriteria.java index 70e697684..10fa38c7b 100644 --- a/openid-connect-server/src/main/java/org/mitre/data/PageCriteria.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/data/PageCriteria.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.data; +package cz.muni.ics.data; /** * Interface which defines page criteria for use in diff --git a/openid-connect-server/src/main/java/org/mitre/discovery/util/WebfingerURLNormalizer.java b/perun-oidc-server/src/main/java/cz/muni/ics/discovery/util/WebfingerURLNormalizer.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/discovery/util/WebfingerURLNormalizer.java rename to perun-oidc-server/src/main/java/cz/muni/ics/discovery/util/WebfingerURLNormalizer.java index c004d1134..70c5f01ce 100644 --- a/openid-connect-server/src/main/java/org/mitre/discovery/util/WebfingerURLNormalizer.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/discovery/util/WebfingerURLNormalizer.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.discovery.util; +package cz.muni.ics.discovery.util; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/openid-connect-server/src/main/java/org/mitre/discovery/view/WebfingerView.java b/perun-oidc-server/src/main/java/cz/muni/ics/discovery/view/WebfingerView.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/discovery/view/WebfingerView.java rename to perun-oidc-server/src/main/java/cz/muni/ics/discovery/view/WebfingerView.java index 527ff4788..0c3888ebb 100644 --- a/openid-connect-server/src/main/java/org/mitre/discovery/view/WebfingerView.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/discovery/view/WebfingerView.java @@ -18,8 +18,9 @@ /** * */ -package org.mitre.discovery.view; +package cz.muni.ics.discovery.view; +import cz.muni.ics.openid.connect.view.HttpCodeView; import java.io.IOException; import java.io.Writer; import java.util.Map; @@ -27,7 +28,6 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.mitre.openid.connect.view.HttpCodeView; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; diff --git a/openid-connect-server/src/main/java/org/mitre/discovery/web/DiscoveryEndpoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/discovery/web/DiscoveryEndpoint.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/discovery/web/DiscoveryEndpoint.java rename to perun-oidc-server/src/main/java/cz/muni/ics/discovery/web/DiscoveryEndpoint.java index a74633602..c69f1b358 100644 --- a/openid-connect-server/src/main/java/org/mitre/discovery/web/DiscoveryEndpoint.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/discovery/web/DiscoveryEndpoint.java @@ -15,30 +15,30 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.discovery.web; +package cz.muni.ics.discovery.web; +import cz.muni.ics.discovery.util.WebfingerURLNormalizer; +import cz.muni.ics.jwt.encryption.service.JWTEncryptionAndDecryptionService; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonEntityView; +import cz.muni.ics.openid.connect.web.DynamicClientRegistrationEndpoint; +import cz.muni.ics.openid.connect.web.EndSessionEndpoint; +import cz.muni.ics.openid.connect.web.JWKSetPublishingEndpoint; +import cz.muni.ics.openid.connect.web.UserInfoEndpoint; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; -import org.mitre.discovery.util.WebfingerURLNormalizer; -import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.oauth2.model.PKCEAlgorithm; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.oauth2.web.DeviceEndpoint; -import org.mitre.oauth2.web.IntrospectionEndpoint; -import org.mitre.oauth2.web.RevocationEndpoint; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.service.UserInfoService; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonEntityView; -import org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint; -import org.mitre.openid.connect.web.EndSessionEndpoint; -import org.mitre.openid.connect.web.JWKSetPublishingEndpoint; -import org.mitre.openid.connect.web.UserInfoEndpoint; +import cz.muni.ics.oauth2.model.PKCEAlgorithm; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.oauth2.web.DeviceEndpoint; +import cz.muni.ics.oauth2.web.IntrospectionEndpoint; +import cz.muni.ics.oauth2.web.RevocationEndpoint; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.service.UserInfoService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/jose/keystore/JWKSetKeyStore.java b/perun-oidc-server/src/main/java/cz/muni/ics/jose/keystore/JWKSetKeyStore.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/jose/keystore/JWKSetKeyStore.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jose/keystore/JWKSetKeyStore.java index 37746f4c1..b2e8b2146 100644 --- a/openid-connect-server/src/main/java/org/mitre/jose/keystore/JWKSetKeyStore.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jose/keystore/JWKSetKeyStore.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.jose.keystore; +package cz.muni.ics.jose.keystore; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/assertion/AbstractAssertionValidator.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/AbstractAssertionValidator.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/jwt/assertion/AbstractAssertionValidator.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/AbstractAssertionValidator.java index d989b6010..599aeb610 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/assertion/AbstractAssertionValidator.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/AbstractAssertionValidator.java @@ -1,4 +1,4 @@ -package org.mitre.jwt.assertion; +package cz.muni.ics.jwt.assertion; import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.JWTClaimsSet; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/assertion/AssertionValidator.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/AssertionValidator.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/jwt/assertion/AssertionValidator.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/AssertionValidator.java index 9b1e4e476..5e406831d 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/assertion/AssertionValidator.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/AssertionValidator.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.jwt.assertion; +package cz.muni.ics.jwt.assertion; import com.nimbusds.jwt.JWT; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/assertion/impl/NullAssertionValidator.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/impl/NullAssertionValidator.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/jwt/assertion/impl/NullAssertionValidator.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/impl/NullAssertionValidator.java index 55c443a4d..df6083e23 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/assertion/impl/NullAssertionValidator.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/impl/NullAssertionValidator.java @@ -14,9 +14,9 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.jwt.assertion.impl; +package cz.muni.ics.jwt.assertion.impl; -import org.mitre.jwt.assertion.AssertionValidator; +import cz.muni.ics.jwt.assertion.AssertionValidator; import com.nimbusds.jwt.JWT; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/assertion/impl/SelfAssertionValidator.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/impl/SelfAssertionValidator.java similarity index 87% rename from openid-connect-server/src/main/java/org/mitre/jwt/assertion/impl/SelfAssertionValidator.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/impl/SelfAssertionValidator.java index df028daa0..86e9f8220 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/assertion/impl/SelfAssertionValidator.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/impl/SelfAssertionValidator.java @@ -14,12 +14,12 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.jwt.assertion.impl; +package cz.muni.ics.jwt.assertion.impl; -import org.mitre.jwt.assertion.AbstractAssertionValidator; -import org.mitre.jwt.assertion.AssertionValidator; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.jwt.assertion.AbstractAssertionValidator; +import cz.muni.ics.jwt.assertion.AssertionValidator; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/assertion/impl/WhitelistedIssuerAssertionValidator.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/impl/WhitelistedIssuerAssertionValidator.java similarity index 89% rename from openid-connect-server/src/main/java/org/mitre/jwt/assertion/impl/WhitelistedIssuerAssertionValidator.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/impl/WhitelistedIssuerAssertionValidator.java index ad8d37c8e..ce4086d83 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/assertion/impl/WhitelistedIssuerAssertionValidator.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/assertion/impl/WhitelistedIssuerAssertionValidator.java @@ -14,14 +14,14 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.jwt.assertion.impl; +package cz.muni.ics.jwt.assertion.impl; import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.SignedJWT; -import org.mitre.jwt.assertion.AbstractAssertionValidator; -import org.mitre.jwt.assertion.AssertionValidator; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.jwt.signer.service.impl.JWKSetCacheService; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.jwt.assertion.AbstractAssertionValidator; +import cz.muni.ics.jwt.assertion.AssertionValidator; +import cz.muni.ics.jwt.signer.service.impl.JWKSetCacheService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/encryption/service/JWTEncryptionAndDecryptionService.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/encryption/service/JWTEncryptionAndDecryptionService.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/jwt/encryption/service/JWTEncryptionAndDecryptionService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/encryption/service/JWTEncryptionAndDecryptionService.java index baf7860ce..b3aeca203 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/encryption/service/JWTEncryptionAndDecryptionService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/encryption/service/JWTEncryptionAndDecryptionService.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.jwt.encryption.service; +package cz.muni.ics.jwt.encryption.service; import java.util.Collection; import java.util.Map; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/encryption/service/impl/DefaultJWTEncryptionAndDecryptionService.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/encryption/service/impl/DefaultJWTEncryptionAndDecryptionService.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/jwt/encryption/service/impl/DefaultJWTEncryptionAndDecryptionService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/encryption/service/impl/DefaultJWTEncryptionAndDecryptionService.java index 01213faaf..9d11eaad9 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/encryption/service/impl/DefaultJWTEncryptionAndDecryptionService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/encryption/service/impl/DefaultJWTEncryptionAndDecryptionService.java @@ -15,8 +15,10 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.jwt.encryption.service.impl; +package cz.muni.ics.jwt.encryption.service.impl; +import cz.muni.ics.jose.keystore.JWKSetKeyStore; +import cz.muni.ics.jwt.encryption.service.JWTEncryptionAndDecryptionService; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -26,8 +28,6 @@ import java.util.Set; import javax.annotation.PostConstruct; import com.nimbusds.jose.KeyLengthException; -import org.mitre.jose.keystore.JWKSetKeyStore; -import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/signer/service/JWTSigningAndValidationService.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/JWTSigningAndValidationService.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/jwt/signer/service/JWTSigningAndValidationService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/JWTSigningAndValidationService.java index 582e2c39a..abac18917 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/signer/service/JWTSigningAndValidationService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/JWTSigningAndValidationService.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.jwt.signer.service; +package cz.muni.ics.jwt.signer.service; import java.security.NoSuchAlgorithmException; import java.util.Collection; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/ClientKeyCacheService.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/ClientKeyCacheService.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/ClientKeyCacheService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/ClientKeyCacheService.java index 5f6866ff6..2e10c0e4f 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/ClientKeyCacheService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/ClientKeyCacheService.java @@ -14,19 +14,19 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.jwt.signer.service.impl; +package cz.muni.ics.jwt.signer.service.impl; +import cz.muni.ics.jose.keystore.JWKSetKeyStore; +import cz.muni.ics.jwt.encryption.service.JWTEncryptionAndDecryptionService; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import org.mitre.jose.keystore.JWKSetKeyStore; -import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService; -import org.mitre.jwt.encryption.service.impl.DefaultJWTEncryptionAndDecryptionService; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.jwt.encryption.service.impl.DefaultJWTEncryptionAndDecryptionService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/DefaultJWTSigningAndValidationService.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/DefaultJWTSigningAndValidationService.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/DefaultJWTSigningAndValidationService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/DefaultJWTSigningAndValidationService.java index 34a97ff30..0d4ffc083 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/DefaultJWTSigningAndValidationService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/DefaultJWTSigningAndValidationService.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.jwt.signer.service.impl; +package cz.muni.ics.jwt.signer.service.impl; import com.nimbusds.jose.JOSEException; @@ -34,8 +34,8 @@ import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.OctetSequenceKey; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jwt.SignedJWT; -import org.mitre.jose.keystore.JWKSetKeyStore; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.jose.keystore.JWKSetKeyStore; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/JWKSetCacheService.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/JWKSetCacheService.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/JWKSetCacheService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/JWKSetCacheService.java index 227550c96..b4bf5979a 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/JWKSetCacheService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/JWKSetCacheService.java @@ -18,17 +18,17 @@ /** * */ -package org.mitre.jwt.signer.service.impl; +package cz.muni.ics.jwt.signer.service.impl; +import cz.muni.ics.jose.keystore.JWKSetKeyStore; +import cz.muni.ics.jwt.encryption.service.JWTEncryptionAndDecryptionService; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.HttpClientBuilder; -import org.mitre.jose.keystore.JWKSetKeyStore; -import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService; -import org.mitre.jwt.encryption.service.impl.DefaultJWTEncryptionAndDecryptionService; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.jwt.encryption.service.impl.DefaultJWTEncryptionAndDecryptionService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/SymmetricKeyJWTValidatorCacheService.java b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/SymmetricKeyJWTValidatorCacheService.java similarity index 94% rename from openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/SymmetricKeyJWTValidatorCacheService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/SymmetricKeyJWTValidatorCacheService.java index 3a40559c5..b88bab051 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/signer/service/impl/SymmetricKeyJWTValidatorCacheService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/jwt/signer/service/impl/SymmetricKeyJWTValidatorCacheService.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.jwt.signer.service.impl; +package cz.muni.ics.jwt.signer.service.impl; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; @@ -24,8 +24,8 @@ import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.KeyUse; import com.nimbusds.jose.jwk.OctetSequenceKey; import com.nimbusds.jose.util.Base64URL; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; diff --git a/openid-connect-server/src/main/java/org/mitre/mdc/MultiMDCFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/mdc/MultiMDCFilter.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/mdc/MultiMDCFilter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/mdc/MultiMDCFilter.java index 27850a2e4..8f8b6b00c 100644 --- a/openid-connect-server/src/main/java/org/mitre/mdc/MultiMDCFilter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/mdc/MultiMDCFilter.java @@ -1,4 +1,4 @@ -package org.mitre.mdc; +package cz.muni.ics.mdc; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/openid-connect-server/src/main/java/org/mitre/mdc/RemoteAddressMDCFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/mdc/RemoteAddressMDCFilter.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/mdc/RemoteAddressMDCFilter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/mdc/RemoteAddressMDCFilter.java index 45b6beb46..82aa2e92c 100644 --- a/openid-connect-server/src/main/java/org/mitre/mdc/RemoteAddressMDCFilter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/mdc/RemoteAddressMDCFilter.java @@ -1,4 +1,4 @@ -package org.mitre.mdc; +package cz.muni.ics.mdc; import org.slf4j.MDC; diff --git a/openid-connect-server/src/main/java/org/mitre/mdc/SessionIdMDCFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/mdc/SessionIdMDCFilter.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/mdc/SessionIdMDCFilter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/mdc/SessionIdMDCFilter.java index 85f95de87..563aff710 100644 --- a/openid-connect-server/src/main/java/org/mitre/mdc/SessionIdMDCFilter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/mdc/SessionIdMDCFilter.java @@ -1,4 +1,4 @@ -package org.mitre.mdc; +package cz.muni.ics.mdc; import org.slf4j.MDC; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/assertion/AssertionOAuth2RequestFactory.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/assertion/AssertionOAuth2RequestFactory.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/oauth2/assertion/AssertionOAuth2RequestFactory.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/assertion/AssertionOAuth2RequestFactory.java index 729d8a30d..e27e7f21d 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/assertion/AssertionOAuth2RequestFactory.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/assertion/AssertionOAuth2RequestFactory.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.assertion; +package cz.muni.ics.oauth2.assertion; import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.security.oauth2.provider.OAuth2Request; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/assertion/impl/DirectCopyRequestFactory.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/assertion/impl/DirectCopyRequestFactory.java similarity index 94% rename from openid-connect-server/src/main/java/org/mitre/oauth2/assertion/impl/DirectCopyRequestFactory.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/assertion/impl/DirectCopyRequestFactory.java index 31a7bbd4e..a74bbbeaf 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/assertion/impl/DirectCopyRequestFactory.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/assertion/impl/DirectCopyRequestFactory.java @@ -14,12 +14,12 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.assertion.impl; +package cz.muni.ics.oauth2.assertion.impl; import java.text.ParseException; import java.util.Set; -import org.mitre.oauth2.assertion.AssertionOAuth2RequestFactory; +import cz.muni.ics.oauth2.assertion.AssertionOAuth2RequestFactory; import org.springframework.security.oauth2.common.util.OAuth2Utils; import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.security.oauth2.provider.OAuth2Request; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/exception/AuthorizationPendingException.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/AuthorizationPendingException.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/exception/AuthorizationPendingException.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/AuthorizationPendingException.java index 20ba04b8a..fa10c5553 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/exception/AuthorizationPendingException.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/AuthorizationPendingException.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.exception; +package cz.muni.ics.oauth2.exception; import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/exception/DeviceCodeCreationException.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/DeviceCodeCreationException.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/exception/DeviceCodeCreationException.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/DeviceCodeCreationException.java index dd3bd389f..36700259a 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/exception/DeviceCodeCreationException.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/DeviceCodeCreationException.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.exception; +package cz.muni.ics.oauth2.exception; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/exception/DeviceCodeExpiredException.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/DeviceCodeExpiredException.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/exception/DeviceCodeExpiredException.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/DeviceCodeExpiredException.java index 006760ace..f064a0ec3 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/exception/DeviceCodeExpiredException.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/DeviceCodeExpiredException.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.exception; +package cz.muni.ics.oauth2.exception; import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/exception/DuplicateClientIdException.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/DuplicateClientIdException.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/exception/DuplicateClientIdException.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/DuplicateClientIdException.java index 8e01c86bc..c269df5d6 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/exception/DuplicateClientIdException.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/exception/DuplicateClientIdException.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.exception; +package cz.muni.ics.oauth2.exception; public class DuplicateClientIdException extends RuntimeException { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/AuthenticationHolderEntity.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/AuthenticationHolderEntity.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/AuthenticationHolderEntity.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/AuthenticationHolderEntity.java index e46e8ceb9..936ccc0df 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/AuthenticationHolderEntity.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/AuthenticationHolderEntity.java @@ -15,8 +15,10 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; +import cz.muni.ics.oauth2.model.convert.SerializableStringConverter; +import cz.muni.ics.oauth2.model.convert.SimpleGrantedAuthorityStringConverter; import java.io.Serializable; import java.util.Collection; import java.util.HashMap; @@ -43,8 +45,6 @@ import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Transient; -import org.mitre.oauth2.model.convert.SerializableStringConverter; -import org.mitre.oauth2.model.convert.SimpleGrantedAuthorityStringConverter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.OAuth2Request; @@ -186,7 +186,7 @@ public class AuthenticationHolderEntity { @CollectionTable(name="authentication_holder_extension", joinColumns=@JoinColumn(name="owner_id")) @Column(name="val") @MapKeyColumn(name="extension") - @Convert(converter=SerializableStringConverter.class) + @Convert(converter= SerializableStringConverter.class) public Map<String, Serializable> getExtensions() { return extensions; } diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/AuthorizationCodeEntity.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/AuthorizationCodeEntity.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/AuthorizationCodeEntity.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/AuthorizationCodeEntity.java index 98f697af0..be48f34f5 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/AuthorizationCodeEntity.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/AuthorizationCodeEntity.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; import java.util.Date; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/ClientDetailsEntity.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/ClientDetailsEntity.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/ClientDetailsEntity.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/ClientDetailsEntity.java index 08c716002..330db1dc7 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/ClientDetailsEntity.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/ClientDetailsEntity.java @@ -18,20 +18,20 @@ /** * */ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; import com.nimbusds.jose.EncryptionMethod; import com.nimbusds.jose.JWEAlgorithm; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jwt.JWT; -import org.mitre.oauth2.model.convert.JWEAlgorithmStringConverter; -import org.mitre.oauth2.model.convert.JWEEncryptionMethodStringConverter; -import org.mitre.oauth2.model.convert.JWKSetStringConverter; -import org.mitre.oauth2.model.convert.JWSAlgorithmStringConverter; -import org.mitre.oauth2.model.convert.JWTStringConverter; -import org.mitre.oauth2.model.convert.PKCEAlgorithmStringConverter; -import org.mitre.oauth2.model.convert.SimpleGrantedAuthorityStringConverter; +import cz.muni.ics.oauth2.model.convert.JWEAlgorithmStringConverter; +import cz.muni.ics.oauth2.model.convert.JWEEncryptionMethodStringConverter; +import cz.muni.ics.oauth2.model.convert.JWKSetStringConverter; +import cz.muni.ics.oauth2.model.convert.JWSAlgorithmStringConverter; +import cz.muni.ics.oauth2.model.convert.JWTStringConverter; +import cz.muni.ics.oauth2.model.convert.PKCEAlgorithmStringConverter; +import cz.muni.ics.oauth2.model.convert.SimpleGrantedAuthorityStringConverter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.provider.ClientDetails; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/DeviceCode.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/DeviceCode.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/DeviceCode.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/DeviceCode.java index b34a33ed2..bbf864df3 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/DeviceCode.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/DeviceCode.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; import java.util.Date; import java.util.Map; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/OAuth2AccessTokenEntity.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/OAuth2AccessTokenEntity.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/OAuth2AccessTokenEntity.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/OAuth2AccessTokenEntity.java index e702910db..811a49e88 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/OAuth2AccessTokenEntity.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/OAuth2AccessTokenEntity.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; import java.util.Date; import java.util.HashMap; @@ -46,9 +46,9 @@ import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.Transient; -import org.mitre.oauth2.model.convert.JWTStringConverter; -import org.mitre.openid.connect.model.ApprovedSite; -import org.mitre.uma.model.Permission; +import cz.muni.ics.oauth2.model.convert.JWTStringConverter; +import cz.muni.ics.openid.connect.model.ApprovedSite; +import cz.muni.ics.uma.model.Permission; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2AccessTokenJackson2Deserializer; import org.springframework.security.oauth2.common.OAuth2AccessTokenJackson2Serializer; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/OAuth2RefreshTokenEntity.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/OAuth2RefreshTokenEntity.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/OAuth2RefreshTokenEntity.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/OAuth2RefreshTokenEntity.java index a1bd2288c..67f98f808 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/OAuth2RefreshTokenEntity.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/OAuth2RefreshTokenEntity.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; import java.util.Date; @@ -38,7 +38,7 @@ import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.Transient; -import org.mitre.oauth2.model.convert.JWTStringConverter; +import cz.muni.ics.oauth2.model.convert.JWTStringConverter; import org.springframework.security.oauth2.common.OAuth2RefreshToken; import com.nimbusds.jwt.JWT; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/PKCEAlgorithm.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/PKCEAlgorithm.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/PKCEAlgorithm.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/PKCEAlgorithm.java index ab86effcc..c52b7be1e 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/PKCEAlgorithm.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/PKCEAlgorithm.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; import com.nimbusds.jose.Algorithm; import com.nimbusds.jose.Requirement; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/RegisteredClient.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/RegisteredClient.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/RegisteredClient.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/RegisteredClient.java index 454e702b9..0a3f2efa2 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/RegisteredClient.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/RegisteredClient.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; import com.google.gson.JsonObject; import com.nimbusds.jose.EncryptionMethod; @@ -26,9 +26,6 @@ import com.nimbusds.jose.JWEAlgorithm; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jwt.JWT; -import org.mitre.oauth2.model.ClientDetailsEntity.AppType; -import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod; -import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType; import org.springframework.security.core.GrantedAuthority; import java.util.Date; @@ -205,11 +202,11 @@ public class RegisteredClient { return client.getAdditionalInformation(); } - public AppType getApplicationType() { + public ClientDetailsEntity.AppType getApplicationType() { return client.getApplicationType(); } - public void setApplicationType(AppType applicationType) { + public void setApplicationType(ClientDetailsEntity.AppType applicationType) { client.setApplicationType(applicationType); } @@ -221,19 +218,19 @@ public class RegisteredClient { client.setClientName(clientName); } - public AuthMethod getTokenEndpointAuthMethod() { + public ClientDetailsEntity.AuthMethod getTokenEndpointAuthMethod() { return client.getTokenEndpointAuthMethod(); } - public void setTokenEndpointAuthMethod(AuthMethod tokenEndpointAuthMethod) { + public void setTokenEndpointAuthMethod(ClientDetailsEntity.AuthMethod tokenEndpointAuthMethod) { client.setTokenEndpointAuthMethod(tokenEndpointAuthMethod); } - public SubjectType getSubjectType() { + public ClientDetailsEntity.SubjectType getSubjectType() { return client.getSubjectType(); } - public void setSubjectType(SubjectType subjectType) { + public void setSubjectType(ClientDetailsEntity.SubjectType subjectType) { client.setSubjectType(subjectType); } diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/RegisteredClientFields.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/RegisteredClientFields.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/RegisteredClientFields.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/RegisteredClientFields.java index b334c4827..8803ec74b 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/RegisteredClientFields.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/RegisteredClientFields.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; public interface RegisteredClientFields { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/SavedUserAuthentication.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/SavedUserAuthentication.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/SavedUserAuthentication.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/SavedUserAuthentication.java index dfe4829e8..b085e5d0c 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/SavedUserAuthentication.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/SavedUserAuthentication.java @@ -14,8 +14,9 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; +import cz.muni.ics.oauth2.model.convert.SimpleGrantedAuthorityStringConverter; import java.util.Collection; import java.util.HashSet; @@ -33,7 +34,6 @@ import javax.persistence.JoinColumn; import javax.persistence.Table; import javax.persistence.Transient; -import org.mitre.oauth2.model.convert.SimpleGrantedAuthorityStringConverter; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/SystemScope.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/SystemScope.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/SystemScope.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/SystemScope.java index 78f858dbc..70fd23476 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/SystemScope.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/SystemScope.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; import javax.persistence.Basic; import javax.persistence.Column; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWEAlgorithmStringConverter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWEAlgorithmStringConverter.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWEAlgorithmStringConverter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWEAlgorithmStringConverter.java index 729e36b66..bbb562dc0 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWEAlgorithmStringConverter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWEAlgorithmStringConverter.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model.convert; +package cz.muni.ics.oauth2.model.convert; import javax.persistence.AttributeConverter; import javax.persistence.Converter; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWEEncryptionMethodStringConverter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWEEncryptionMethodStringConverter.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWEEncryptionMethodStringConverter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWEEncryptionMethodStringConverter.java index 21a50fd62..3d154cdba 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWEEncryptionMethodStringConverter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWEEncryptionMethodStringConverter.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model.convert; +package cz.muni.ics.oauth2.model.convert; import javax.persistence.AttributeConverter; import javax.persistence.Converter; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWKSetStringConverter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWKSetStringConverter.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWKSetStringConverter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWKSetStringConverter.java index e3f8e7bde..0e23e1a9a 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWKSetStringConverter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWKSetStringConverter.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model.convert; +package cz.muni.ics.oauth2.model.convert; import java.text.ParseException; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWSAlgorithmStringConverter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWSAlgorithmStringConverter.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWSAlgorithmStringConverter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWSAlgorithmStringConverter.java index 6d35d0044..c5e31e52b 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWSAlgorithmStringConverter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWSAlgorithmStringConverter.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model.convert; +package cz.muni.ics.oauth2.model.convert; import javax.persistence.AttributeConverter; import javax.persistence.Converter; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWTStringConverter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWTStringConverter.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWTStringConverter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWTStringConverter.java index dfae2cf30..f9b79f2c9 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JWTStringConverter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JWTStringConverter.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model.convert; +package cz.muni.ics.oauth2.model.convert; import java.text.ParseException; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JsonElementStringConverter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JsonElementStringConverter.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JsonElementStringConverter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JsonElementStringConverter.java index 7a8010c3a..250c6e2b0 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/JsonElementStringConverter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/JsonElementStringConverter.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model.convert; +package cz.muni.ics.oauth2.model.convert; import javax.persistence.AttributeConverter; import javax.persistence.Converter; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/PKCEAlgorithmStringConverter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/PKCEAlgorithmStringConverter.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/PKCEAlgorithmStringConverter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/PKCEAlgorithmStringConverter.java index 5fa2b2608..a201f07fe 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/PKCEAlgorithmStringConverter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/PKCEAlgorithmStringConverter.java @@ -14,12 +14,12 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model.convert; +package cz.muni.ics.oauth2.model.convert; import javax.persistence.AttributeConverter; import javax.persistence.Converter; -import org.mitre.oauth2.model.PKCEAlgorithm; +import cz.muni.ics.oauth2.model.PKCEAlgorithm; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/SerializableStringConverter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/SerializableStringConverter.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/SerializableStringConverter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/SerializableStringConverter.java index 27dfdccef..5844cf905 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/SerializableStringConverter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/SerializableStringConverter.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model.convert; +package cz.muni.ics.oauth2.model.convert; import java.io.Serializable; import java.util.Date; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/SimpleGrantedAuthorityStringConverter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/SimpleGrantedAuthorityStringConverter.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/SimpleGrantedAuthorityStringConverter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/SimpleGrantedAuthorityStringConverter.java index 6ff460bcb..3e867ca72 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/model/convert/SimpleGrantedAuthorityStringConverter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/convert/SimpleGrantedAuthorityStringConverter.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.model.convert; +package cz.muni.ics.oauth2.model.convert; import javax.persistence.AttributeConverter; import javax.persistence.Converter; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/AuthenticationHolderRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/AuthenticationHolderRepository.java similarity index 90% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/AuthenticationHolderRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/AuthenticationHolderRepository.java index 9666d910f..2d7b50405 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/AuthenticationHolderRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/AuthenticationHolderRepository.java @@ -15,12 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.repository; +package cz.muni.ics.oauth2.repository; +import cz.muni.ics.data.PageCriteria; import java.util.List; -import org.mitre.data.PageCriteria; -import org.mitre.oauth2.model.AuthenticationHolderEntity; +import cz.muni.ics.oauth2.model.AuthenticationHolderEntity; public interface AuthenticationHolderRepository { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/AuthorizationCodeRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/AuthorizationCodeRepository.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/AuthorizationCodeRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/AuthorizationCodeRepository.java index 0cff24b10..ab669cecd 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/AuthorizationCodeRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/AuthorizationCodeRepository.java @@ -15,12 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.repository; +package cz.muni.ics.oauth2.repository; +import cz.muni.ics.data.PageCriteria; import java.util.Collection; -import org.mitre.data.PageCriteria; -import org.mitre.oauth2.model.AuthorizationCodeEntity; +import cz.muni.ics.oauth2.model.AuthorizationCodeEntity; /** * Interface for saving and consuming OAuth2 authorization codes as AuthorizationCodeEntitys. diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/OAuth2ClientRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/OAuth2ClientRepository.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/OAuth2ClientRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/OAuth2ClientRepository.java index 00c70ee34..5288528af 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/OAuth2ClientRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/OAuth2ClientRepository.java @@ -15,11 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.repository; +package cz.muni.ics.oauth2.repository; import java.util.Collection; -import org.mitre.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; public interface OAuth2ClientRepository { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/OAuth2TokenRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/OAuth2TokenRepository.java similarity index 90% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/OAuth2TokenRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/OAuth2TokenRepository.java index 8465fcb0d..80032c7e3 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/OAuth2TokenRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/OAuth2TokenRepository.java @@ -15,17 +15,17 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.repository; +package cz.muni.ics.oauth2.repository; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; import java.util.List; import java.util.Set; -import org.mitre.data.PageCriteria; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.openid.connect.model.ApprovedSite; -import org.mitre.uma.model.ResourceSet; +import cz.muni.ics.data.PageCriteria; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.openid.connect.model.ApprovedSite; +import cz.muni.ics.uma.model.ResourceSet; public interface OAuth2TokenRepository { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/SystemScopeRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/SystemScopeRepository.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/SystemScopeRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/SystemScopeRepository.java index 022ef8388..ccd745f4f 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/SystemScopeRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/SystemScopeRepository.java @@ -18,11 +18,11 @@ /** * */ -package org.mitre.oauth2.repository; +package cz.muni.ics.oauth2.repository; import java.util.Set; -import org.mitre.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.model.SystemScope; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/DeviceCodeRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/DeviceCodeRepository.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/DeviceCodeRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/DeviceCodeRepository.java index 94d408689..10bc0c604 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/DeviceCodeRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/DeviceCodeRepository.java @@ -14,11 +14,11 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.repository.impl; +package cz.muni.ics.oauth2.repository.impl; import java.util.Collection; -import org.mitre.oauth2.model.DeviceCode; +import cz.muni.ics.oauth2.model.DeviceCode; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaAuthenticationHolderRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaAuthenticationHolderRepository.java similarity index 90% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaAuthenticationHolderRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaAuthenticationHolderRepository.java index 7dcbef06d..7f765405b 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaAuthenticationHolderRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaAuthenticationHolderRepository.java @@ -15,19 +15,19 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.repository.impl; +package cz.muni.ics.oauth2.repository.impl; +import cz.muni.ics.data.DefaultPageCriteria; +import cz.muni.ics.data.PageCriteria; +import cz.muni.ics.util.jpa.JpaUtil; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; -import org.mitre.data.DefaultPageCriteria; -import org.mitre.data.PageCriteria; -import org.mitre.oauth2.model.AuthenticationHolderEntity; -import org.mitre.oauth2.repository.AuthenticationHolderRepository; -import org.mitre.util.jpa.JpaUtil; +import cz.muni.ics.oauth2.model.AuthenticationHolderEntity; +import cz.muni.ics.oauth2.repository.AuthenticationHolderRepository; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaAuthorizationCodeRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaAuthorizationCodeRepository.java similarity index 82% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaAuthorizationCodeRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaAuthorizationCodeRepository.java index 8209800d3..b2f202bf3 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaAuthorizationCodeRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaAuthorizationCodeRepository.java @@ -18,8 +18,11 @@ /** * */ -package org.mitre.oauth2.repository.impl; +package cz.muni.ics.oauth2.repository.impl; +import cz.muni.ics.data.PageCriteria; +import cz.muni.ics.oauth2.repository.AuthorizationCodeRepository; +import cz.muni.ics.util.jpa.JpaUtil; import java.util.Collection; import java.util.Date; @@ -27,10 +30,7 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; -import org.mitre.data.PageCriteria; -import org.mitre.oauth2.model.AuthorizationCodeEntity; -import org.mitre.oauth2.repository.AuthorizationCodeRepository; -import org.mitre.util.jpa.JpaUtil; +import cz.muni.ics.oauth2.model.AuthorizationCodeEntity; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -48,7 +48,7 @@ public class JpaAuthorizationCodeRepository implements AuthorizationCodeReposito EntityManager manager; /* (non-Javadoc) - * @see org.mitre.oauth2.repository.AuthorizationCodeRepository#save(org.mitre.oauth2.model.AuthorizationCodeEntity) + * @see cz.muni.ics.oauth2.repository.AuthorizationCodeRepository#save(cz.muni.ics.oauth2.model.AuthorizationCodeEntity) */ @Override @Transactional(value="defaultTransactionManager") @@ -59,7 +59,7 @@ public class JpaAuthorizationCodeRepository implements AuthorizationCodeReposito } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.AuthorizationCodeRepository#getByCode(java.lang.String) + * @see cz.muni.ics.oauth2.repository.AuthorizationCodeRepository#getByCode(java.lang.String) */ @Override @Transactional(value="defaultTransactionManager") @@ -72,7 +72,7 @@ public class JpaAuthorizationCodeRepository implements AuthorizationCodeReposito } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.AuthorizationCodeRepository#remove(org.mitre.oauth2.model.AuthorizationCodeEntity) + * @see cz.muni.ics.oauth2.repository.AuthorizationCodeRepository#remove(cz.muni.ics.oauth2.model.AuthorizationCodeEntity) */ @Override public void remove(AuthorizationCodeEntity authorizationCodeEntity) { @@ -83,7 +83,7 @@ public class JpaAuthorizationCodeRepository implements AuthorizationCodeReposito } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.AuthorizationCodeRepository#getExpiredCodes() + * @see cz.muni.ics.oauth2.repository.AuthorizationCodeRepository#getExpiredCodes() */ @Override public Collection<AuthorizationCodeEntity> getExpiredCodes() { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaDeviceCodeRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaDeviceCodeRepository.java similarity index 84% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaDeviceCodeRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaDeviceCodeRepository.java index 50304adab..33535e993 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaDeviceCodeRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaDeviceCodeRepository.java @@ -16,11 +16,9 @@ /** * */ -package org.mitre.oauth2.repository.impl; - -import static org.mitre.util.jpa.JpaUtil.getSingleResult; -import static org.mitre.util.jpa.JpaUtil.saveOrUpdate; +package cz.muni.ics.oauth2.repository.impl; +import cz.muni.ics.util.jpa.JpaUtil; import java.util.Collection; import java.util.Date; @@ -28,7 +26,7 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; -import org.mitre.oauth2.model.DeviceCode; +import cz.muni.ics.oauth2.model.DeviceCode; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -57,7 +55,7 @@ public class JpaDeviceCodeRepository implements DeviceCodeRepository { public DeviceCode getByUserCode(String value) { TypedQuery<DeviceCode> query = em.createNamedQuery(DeviceCode.QUERY_BY_USER_CODE, DeviceCode.class); query.setParameter(DeviceCode.PARAM_USER_CODE, value); - return getSingleResult(query.getResultList()); + return JpaUtil.getSingleResult(query.getResultList()); } /* (non-Javadoc) @@ -67,7 +65,7 @@ public class JpaDeviceCodeRepository implements DeviceCodeRepository { public DeviceCode getByDeviceCode(String value) { TypedQuery<DeviceCode> query = em.createNamedQuery(DeviceCode.QUERY_BY_DEVICE_CODE, DeviceCode.class); query.setParameter(DeviceCode.PARAM_DEVICE_CODE, value); - return getSingleResult(query.getResultList()); + return JpaUtil.getSingleResult(query.getResultList()); } /* (non-Javadoc) @@ -84,16 +82,16 @@ public class JpaDeviceCodeRepository implements DeviceCodeRepository { } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.SystemScopeRepository#save(org.mitre.oauth2.model.SystemScope) + * @see cz.muni.ics.oauth2.repository.SystemScopeRepository#save(cz.muni.ics.oauth2.model.SystemScope) */ @Override @Transactional(value="defaultTransactionManager") public DeviceCode save(DeviceCode scope) { - return saveOrUpdate(em, scope); + return JpaUtil.saveOrUpdate(em, scope); } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.impl.DeviceCodeRepository#getExpiredCodes() + * @see cz.muni.ics.oauth2.repository.impl.DeviceCodeRepository#getExpiredCodes() */ @Override @Transactional(value="defaultTransactionManager") diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaOAuth2ClientRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaOAuth2ClientRepository.java similarity index 84% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaOAuth2ClientRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaOAuth2ClientRepository.java index 7ac796d03..ea359a8bd 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaOAuth2ClientRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaOAuth2ClientRepository.java @@ -15,17 +15,17 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.repository.impl; +package cz.muni.ics.oauth2.repository.impl; +import cz.muni.ics.util.jpa.JpaUtil; import java.util.Collection; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.repository.OAuth2ClientRepository; -import org.mitre.util.jpa.JpaUtil; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.repository.OAuth2ClientRepository; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -54,7 +54,7 @@ public class JpaOAuth2ClientRepository implements OAuth2ClientRepository { } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.OAuth2ClientRepository#getClientById(java.lang.String) + * @see cz.muni.ics.oauth2.repository.OAuth2ClientRepository#getClientById(java.lang.String) */ @Override public ClientDetailsEntity getClientByClientId(String clientId) { @@ -64,7 +64,7 @@ public class JpaOAuth2ClientRepository implements OAuth2ClientRepository { } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.OAuth2ClientRepository#saveClient(org.mitre.oauth2.model.ClientDetailsEntity) + * @see cz.muni.ics.oauth2.repository.OAuth2ClientRepository#saveClient(cz.muni.ics.oauth2.model.ClientDetailsEntity) */ @Override public ClientDetailsEntity saveClient(ClientDetailsEntity client) { @@ -72,7 +72,7 @@ public class JpaOAuth2ClientRepository implements OAuth2ClientRepository { } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.OAuth2ClientRepository#deleteClient(org.mitre.oauth2.model.ClientDetailsEntity) + * @see cz.muni.ics.oauth2.repository.OAuth2ClientRepository#deleteClient(cz.muni.ics.oauth2.model.ClientDetailsEntity) */ @Override public void deleteClient(ClientDetailsEntity client) { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaOAuth2TokenRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaOAuth2TokenRepository.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaOAuth2TokenRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaOAuth2TokenRepository.java index 627dbde27..78578ba5e 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaOAuth2TokenRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaOAuth2TokenRepository.java @@ -15,8 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.repository.impl; +package cz.muni.ics.oauth2.repository.impl; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; +import cz.muni.ics.oauth2.repository.OAuth2TokenRepository; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; @@ -33,15 +36,12 @@ import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaDelete; import javax.persistence.criteria.Root; -import org.mitre.data.DefaultPageCriteria; -import org.mitre.data.PageCriteria; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.oauth2.repository.OAuth2TokenRepository; -import org.mitre.openid.connect.model.ApprovedSite; -import org.mitre.uma.model.ResourceSet; -import org.mitre.util.jpa.JpaUtil; +import cz.muni.ics.data.DefaultPageCriteria; +import cz.muni.ics.data.PageCriteria; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.openid.connect.model.ApprovedSite; +import cz.muni.ics.uma.model.ResourceSet; +import cz.muni.ics.util.jpa.JpaUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Repository; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaSystemScopeRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaSystemScopeRepository.java similarity index 75% rename from openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaSystemScopeRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaSystemScopeRepository.java index ca483cbed..6bca112d7 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaSystemScopeRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/repository/impl/JpaSystemScopeRepository.java @@ -18,11 +18,9 @@ /** * */ -package org.mitre.oauth2.repository.impl; - -import static org.mitre.util.jpa.JpaUtil.getSingleResult; -import static org.mitre.util.jpa.JpaUtil.saveOrUpdate; +package cz.muni.ics.oauth2.repository.impl; +import cz.muni.ics.util.jpa.JpaUtil; import java.util.LinkedHashSet; import java.util.Set; @@ -30,8 +28,8 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.repository.SystemScopeRepository; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.repository.SystemScopeRepository; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -46,7 +44,7 @@ public class JpaSystemScopeRepository implements SystemScopeRepository { private EntityManager em; /* (non-Javadoc) - * @see org.mitre.oauth2.repository.SystemScopeRepository#getAll() + * @see cz.muni.ics.oauth2.repository.SystemScopeRepository#getAll() */ @Override @Transactional(value="defaultTransactionManager") @@ -57,7 +55,7 @@ public class JpaSystemScopeRepository implements SystemScopeRepository { } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.SystemScopeRepository#getById(java.lang.Long) + * @see cz.muni.ics.oauth2.repository.SystemScopeRepository#getById(java.lang.Long) */ @Override @Transactional(value="defaultTransactionManager") @@ -66,18 +64,18 @@ public class JpaSystemScopeRepository implements SystemScopeRepository { } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.SystemScopeRepository#getByValue(java.lang.String) + * @see cz.muni.ics.oauth2.repository.SystemScopeRepository#getByValue(java.lang.String) */ @Override @Transactional(value="defaultTransactionManager") public SystemScope getByValue(String value) { TypedQuery<SystemScope> query = em.createNamedQuery(SystemScope.QUERY_BY_VALUE, SystemScope.class); query.setParameter(SystemScope.PARAM_VALUE, value); - return getSingleResult(query.getResultList()); + return JpaUtil.getSingleResult(query.getResultList()); } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.SystemScopeRepository#remove(org.mitre.oauth2.model.SystemScope) + * @see cz.muni.ics.oauth2.repository.SystemScopeRepository#remove(cz.muni.ics.oauth2.model.SystemScope) */ @Override @Transactional(value="defaultTransactionManager") @@ -91,12 +89,12 @@ public class JpaSystemScopeRepository implements SystemScopeRepository { } /* (non-Javadoc) - * @see org.mitre.oauth2.repository.SystemScopeRepository#save(org.mitre.oauth2.model.SystemScope) + * @see cz.muni.ics.oauth2.repository.SystemScopeRepository#save(cz.muni.ics.oauth2.model.SystemScope) */ @Override @Transactional(value="defaultTransactionManager") public SystemScope save(SystemScope scope) { - return saveOrUpdate(em, scope); + return JpaUtil.saveOrUpdate(em, scope); } } diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/ClientDetailsEntityService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/ClientDetailsEntityService.java similarity index 94% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/ClientDetailsEntityService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/ClientDetailsEntityService.java index 08695c675..195aae139 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/ClientDetailsEntityService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/ClientDetailsEntityService.java @@ -15,11 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service; +package cz.muni.ics.oauth2.service; import java.util.Collection; -import org.mitre.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; import org.springframework.security.oauth2.provider.ClientDetailsService; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/DeviceCodeService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/DeviceCodeService.java similarity index 88% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/DeviceCodeService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/DeviceCodeService.java index 85e6adf55..7d878dcc9 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/DeviceCodeService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/DeviceCodeService.java @@ -14,14 +14,14 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service; +package cz.muni.ics.oauth2.service; +import cz.muni.ics.oauth2.exception.DeviceCodeCreationException; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.DeviceCode; import java.util.Map; import java.util.Set; -import org.mitre.oauth2.exception.DeviceCodeCreationException; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.DeviceCode; import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.security.oauth2.provider.OAuth2Authentication; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/IntrospectionResultAssembler.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/IntrospectionResultAssembler.java similarity index 91% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/IntrospectionResultAssembler.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/IntrospectionResultAssembler.java index 84b715c4d..869e8a8e4 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/IntrospectionResultAssembler.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/IntrospectionResultAssembler.java @@ -13,18 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service; +package cz.muni.ics.oauth2.service; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; +import cz.muni.ics.openid.connect.model.UserInfo; import java.text.SimpleDateFormat; import java.util.Map; import java.util.Set; import javax.swing.text.DateFormatter; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.openid.connect.model.UserInfo; - /** * Strategy interface for assembling a token introspection result. */ diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/OAuth2TokenEntityService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/OAuth2TokenEntityService.java similarity index 89% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/OAuth2TokenEntityService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/OAuth2TokenEntityService.java index 76af302e7..1cd636349 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/OAuth2TokenEntityService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/OAuth2TokenEntityService.java @@ -15,14 +15,14 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service; +package cz.muni.ics.oauth2.service; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; import java.util.List; import java.util.Set; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; @@ -30,7 +30,7 @@ import org.springframework.security.oauth2.provider.token.ResourceServerTokenSer public interface OAuth2TokenEntityService extends AuthorizationServerTokenServices, ResourceServerTokenServices { @Override - OAuth2AccessTokenEntity readAccessToken(String accessTokenValue); + OAuth2AccessTokenEntity readAccessToken(String accessTokenValue); OAuth2RefreshTokenEntity getRefreshToken(String refreshTokenValue); diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/SystemScopeService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/SystemScopeService.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/SystemScopeService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/SystemScopeService.java index c4e7f4561..6785682d8 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/SystemScopeService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/SystemScopeService.java @@ -18,16 +18,13 @@ /** * */ -package org.mitre.oauth2.service; +package cz.muni.ics.oauth2.service; +import cz.muni.ics.oauth2.model.SystemScope; import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import org.mitre.oauth2.model.SystemScope; - -import com.google.common.collect.Sets; - /** * @author jricher */ diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/BlacklistAwareRedirectResolver.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/BlacklistAwareRedirectResolver.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/BlacklistAwareRedirectResolver.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/BlacklistAwareRedirectResolver.java index 1218737f3..2afba1a3b 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/BlacklistAwareRedirectResolver.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/BlacklistAwareRedirectResolver.java @@ -16,11 +16,11 @@ /** * */ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.service.BlacklistedSiteService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.service.BlacklistedSiteService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -44,8 +44,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import static org.mitre.oauth2.model.ClientDetailsEntity.AppType.NATIVE; - /** * * A redirect resolver that knows how to check against the blacklisted URIs @@ -173,7 +171,7 @@ public class BlacklistAwareRedirectResolver implements RedirectResolver { boolean userInfoMatch = isEqual(registeredRedirectUri.getUserInfo(), requestedRedirectUri.getUserInfo()); boolean hostMatch = hostMatches(registeredRedirectUri.getHost(), requestedRedirectUri.getHost()); boolean portMatch = true; - if (!NATIVE.equals(applicationType)) { + if (!ClientDetailsEntity.AppType.NATIVE.equals(applicationType)) { portMatch = !matchPorts || registeredRedirectUri.getPort() == requestedRedirectUri.getPort(); } boolean pathMatch = true; @@ -228,7 +226,7 @@ public class BlacklistAwareRedirectResolver implements RedirectResolver { if (this.matchSubdomains) { redirectUriBuilder.host(requestedRedirectUri.getHost()); } - if (!this.matchPorts || NATIVE.equals(applicationType)) { + if (!this.matchPorts || ClientDetailsEntity.AppType.NATIVE.equals(applicationType)) { redirectUriBuilder.port(requestedRedirectUri.getPort()); } if (!this.strictMatch) { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultClientUserDetailsService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultClientUserDetailsService.java similarity index 91% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultClientUserDetailsService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultClientUserDetailsService.java index 81e384352..8b2eda697 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultClientUserDetailsService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultClientUserDetailsService.java @@ -15,11 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.oauth2.service.impl.ServiceUtils; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultDeviceCodeService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultDeviceCodeService.java similarity index 81% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultDeviceCodeService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultDeviceCodeService.java index 29f4ec8d2..9efa1d6ef 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultDeviceCodeService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultDeviceCodeService.java @@ -14,20 +14,20 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; +import cz.muni.ics.data.AbstractPageOperationTemplate; +import cz.muni.ics.oauth2.model.AuthenticationHolderEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.DeviceCode; +import cz.muni.ics.oauth2.repository.impl.DeviceCodeRepository; import java.util.Collection; import java.util.Date; import java.util.Map; import java.util.Set; import java.util.UUID; -import org.mitre.data.AbstractPageOperationTemplate; -import org.mitre.oauth2.model.AuthenticationHolderEntity; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.DeviceCode; -import org.mitre.oauth2.repository.impl.DeviceCodeRepository; -import org.mitre.oauth2.service.DeviceCodeService; +import cz.muni.ics.oauth2.service.DeviceCodeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; import org.springframework.security.oauth2.provider.ClientDetails; @@ -48,7 +48,7 @@ public class DefaultDeviceCodeService implements DeviceCodeService { private RandomValueStringGenerator randomGenerator = new RandomValueStringGenerator(); /* (non-Javadoc) - * @see org.mitre.oauth2.service.DeviceCodeService#save(org.mitre.oauth2.model.DeviceCode) + * @see cz.muni.ics.oauth2.service.DeviceCodeService#save(cz.muni.ics.oauth2.model.DeviceCode) */ @Override public DeviceCode createNewDeviceCode(Set<String> requestedScopes, ClientDetailsEntity client, Map<String, String> parameters) { @@ -71,7 +71,7 @@ public class DefaultDeviceCodeService implements DeviceCodeService { } /* (non-Javadoc) - * @see org.mitre.oauth2.service.DeviceCodeService#lookUpByUserCode(java.lang.String) + * @see cz.muni.ics.oauth2.service.DeviceCodeService#lookUpByUserCode(java.lang.String) */ @Override public DeviceCode lookUpByUserCode(String userCode) { @@ -80,7 +80,7 @@ public class DefaultDeviceCodeService implements DeviceCodeService { } /* (non-Javadoc) - * @see org.mitre.oauth2.service.DeviceCodeService#approveDeviceCode(org.mitre.oauth2.model.DeviceCode) + * @see cz.muni.ics.oauth2.service.DeviceCodeService#approveDeviceCode(cz.muni.ics.oauth2.model.DeviceCode) */ @Override public DeviceCode approveDeviceCode(DeviceCode dc, OAuth2Authentication auth) { @@ -97,7 +97,7 @@ public class DefaultDeviceCodeService implements DeviceCodeService { } /* (non-Javadoc) - * @see org.mitre.oauth2.service.DeviceCodeService#consumeDeviceCode(java.lang.String, org.springframework.security.oauth2.provider.ClientDetails) + * @see cz.muni.ics.oauth2.service.DeviceCodeService#consumeDeviceCode(java.lang.String, org.springframework.security.oauth2.provider.ClientDetails) */ @Override public DeviceCode findDeviceCode(String deviceCode, ClientDetails client) { @@ -121,7 +121,7 @@ public class DefaultDeviceCodeService implements DeviceCodeService { /* (non-Javadoc) - * @see org.mitre.oauth2.service.DeviceCodeService#clearExpiredDeviceCodes() + * @see cz.muni.ics.oauth2.service.DeviceCodeService#clearExpiredDeviceCodes() */ @Override @Transactional(value="defaultTransactionManager") @@ -141,7 +141,7 @@ public class DefaultDeviceCodeService implements DeviceCodeService { } /* (non-Javadoc) - * @see org.mitre.oauth2.service.DeviceCodeService#clearDeviceCode(java.lang.String, org.springframework.security.oauth2.provider.ClientDetails) + * @see cz.muni.ics.oauth2.service.DeviceCodeService#clearDeviceCode(java.lang.String, org.springframework.security.oauth2.provider.ClientDetails) */ @Override public void clearDeviceCode(String deviceCode, ClientDetails client) { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultIntrospectionResultAssembler.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultIntrospectionResultAssembler.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultIntrospectionResultAssembler.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultIntrospectionResultAssembler.java index ea36949fb..bff81d00f 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultIntrospectionResultAssembler.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultIntrospectionResultAssembler.java @@ -13,19 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; import static com.google.common.collect.Maps.newLinkedHashMap; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.uma.model.Permission; import java.text.ParseException; import java.util.Map; import java.util.Set; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.oauth2.service.IntrospectionResultAssembler; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.uma.model.Permission; +import cz.muni.ics.oauth2.service.IntrospectionResultAssembler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.oauth2.provider.OAuth2Authentication; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2AuthorizationCodeService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultOAuth2AuthorizationCodeService.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2AuthorizationCodeService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultOAuth2AuthorizationCodeService.java index b062a1a4a..5d222c1d0 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2AuthorizationCodeService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultOAuth2AuthorizationCodeService.java @@ -18,16 +18,16 @@ /** * */ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; +import cz.muni.ics.data.AbstractPageOperationTemplate; +import cz.muni.ics.oauth2.model.AuthenticationHolderEntity; +import cz.muni.ics.oauth2.model.AuthorizationCodeEntity; +import cz.muni.ics.oauth2.repository.AuthenticationHolderRepository; +import cz.muni.ics.oauth2.repository.AuthorizationCodeRepository; import java.util.Collection; import java.util.Date; -import org.mitre.data.AbstractPageOperationTemplate; -import org.mitre.oauth2.model.AuthenticationHolderEntity; -import org.mitre.oauth2.model.AuthorizationCodeEntity; -import org.mitre.oauth2.repository.AuthenticationHolderRepository; -import org.mitre.oauth2.repository.AuthorizationCodeRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ClientDetailsEntityService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultOAuth2ClientDetailsEntityService.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ClientDetailsEntityService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultOAuth2ClientDetailsEntityService.java index b730329e3..698712e8e 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ClientDetailsEntityService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultOAuth2ClientDetailsEntityService.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; import com.google.common.base.Strings; import com.google.common.cache.CacheBuilder; @@ -24,23 +24,23 @@ import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.UncheckedExecutionException; import com.google.gson.JsonElement; import com.google.gson.JsonParser; +import cz.muni.ics.oauth2.repository.OAuth2TokenRepository; import org.apache.commons.codec.binary.Base64; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.HttpClientBuilder; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.repository.OAuth2ClientRepository; -import org.mitre.oauth2.repository.OAuth2TokenRepository; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.model.WhitelistedSite; -import org.mitre.openid.connect.service.ApprovedSiteService; -import org.mitre.openid.connect.service.BlacklistedSiteService; -import org.mitre.openid.connect.service.WhitelistedSiteService; -import org.mitre.uma.model.ResourceSet; -import org.mitre.uma.service.ResourceSetService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.AuthMethod; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.repository.OAuth2ClientRepository; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.model.WhitelistedSite; +import cz.muni.ics.openid.connect.service.ApprovedSiteService; +import cz.muni.ics.openid.connect.service.BlacklistedSiteService; +import cz.muni.ics.openid.connect.service.WhitelistedSiteService; +import cz.muni.ics.uma.model.ResourceSet; +import cz.muni.ics.uma.service.ResourceSetService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java index 641bf96fa..0f4beb0d1 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java @@ -18,12 +18,15 @@ /** * */ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; -import static org.mitre.openid.connect.request.ConnectRequestParameters.CODE_CHALLENGE; -import static org.mitre.openid.connect.request.ConnectRequestParameters.CODE_CHALLENGE_METHOD; -import static org.mitre.openid.connect.request.ConnectRequestParameters.CODE_VERIFIER; +import static cz.muni.ics.openid.connect.request.ConnectRequestParameters.CODE_CHALLENGE; +import static cz.muni.ics.openid.connect.request.ConnectRequestParameters.CODE_CHALLENGE_METHOD; +import static cz.muni.ics.openid.connect.request.ConnectRequestParameters.CODE_VERIFIER; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; +import cz.muni.ics.oauth2.repository.OAuth2TokenRepository; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -34,21 +37,18 @@ import java.util.List; import java.util.Set; import java.util.UUID; -import org.mitre.data.AbstractPageOperationTemplate; -import org.mitre.data.DefaultPageCriteria; -import org.mitre.oauth2.model.AuthenticationHolderEntity; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.oauth2.model.PKCEAlgorithm; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.repository.AuthenticationHolderRepository; -import org.mitre.oauth2.repository.OAuth2TokenRepository; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.OAuth2TokenEntityService; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.model.ApprovedSite; -import org.mitre.openid.connect.service.ApprovedSiteService; +import cz.muni.ics.data.AbstractPageOperationTemplate; +import cz.muni.ics.data.DefaultPageCriteria; +import cz.muni.ics.oauth2.model.AuthenticationHolderEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.PKCEAlgorithm; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.repository.AuthenticationHolderRepository; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.oauth2.service.OAuth2TokenEntityService; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.model.ApprovedSite; +import cz.muni.ics.openid.connect.service.ApprovedSiteService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -508,7 +508,7 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi } /* (non-Javadoc) - * @see org.mitre.oauth2.service.OAuth2TokenEntityService#saveAccessToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity) + * @see cz.muni.ics.oauth2.service.OAuth2TokenEntityService#saveAccessToken(cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity) */ @Override @Transactional(value="defaultTransactionManager") @@ -524,7 +524,7 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi } /* (non-Javadoc) - * @see org.mitre.oauth2.service.OAuth2TokenEntityService#saveRefreshToken(org.mitre.oauth2.model.OAuth2RefreshTokenEntity) + * @see cz.muni.ics.oauth2.service.OAuth2TokenEntityService#saveRefreshToken(cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity) */ @Override @Transactional(value="defaultTransactionManager") diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultSystemScopeService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultSystemScopeService.java similarity index 85% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultSystemScopeService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultSystemScopeService.java index 21474fe6e..7b14305ce 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultSystemScopeService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultSystemScopeService.java @@ -18,14 +18,14 @@ /** * */ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.repository.SystemScopeRepository; import java.util.LinkedHashSet; import java.util.Set; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.repository.SystemScopeRepository; -import org.mitre.oauth2.service.SystemScopeService; +import cz.muni.ics.oauth2.service.SystemScopeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -97,7 +97,7 @@ public class DefaultSystemScopeService implements SystemScopeService { }; /* (non-Javadoc) - * @see org.mitre.oauth2.service.SystemScopeService#getAll() + * @see cz.muni.ics.oauth2.service.SystemScopeService#getAll() */ @Override public Set<SystemScope> getAll() { @@ -105,7 +105,7 @@ public class DefaultSystemScopeService implements SystemScopeService { } /* (non-Javadoc) - * @see org.mitre.oauth2.service.SystemScopeService#getById(java.lang.Long) + * @see cz.muni.ics.oauth2.service.SystemScopeService#getById(java.lang.Long) */ @Override public SystemScope getById(Long id) { @@ -113,7 +113,7 @@ public class DefaultSystemScopeService implements SystemScopeService { } /* (non-Javadoc) - * @see org.mitre.oauth2.service.SystemScopeService#getByValue(java.lang.String) + * @see cz.muni.ics.oauth2.service.SystemScopeService#getByValue(java.lang.String) */ @Override public SystemScope getByValue(String value) { @@ -121,7 +121,7 @@ public class DefaultSystemScopeService implements SystemScopeService { } /* (non-Javadoc) - * @see org.mitre.oauth2.service.SystemScopeService#remove(org.mitre.oauth2.model.SystemScope) + * @see cz.muni.ics.oauth2.service.SystemScopeService#remove(cz.muni.ics.oauth2.model.SystemScope) */ @Override public void remove(SystemScope scope) { @@ -130,7 +130,7 @@ public class DefaultSystemScopeService implements SystemScopeService { } /* (non-Javadoc) - * @see org.mitre.oauth2.service.SystemScopeService#save(org.mitre.oauth2.model.SystemScope) + * @see cz.muni.ics.oauth2.service.SystemScopeService#save(cz.muni.ics.oauth2.model.SystemScope) */ @Override public SystemScope save(SystemScope scope) { @@ -142,7 +142,7 @@ public class DefaultSystemScopeService implements SystemScopeService { } /* (non-Javadoc) - * @see org.mitre.oauth2.service.SystemScopeService#fromStrings(java.util.Set) + * @see cz.muni.ics.oauth2.service.SystemScopeService#fromStrings(java.util.Set) */ @Override public Set<SystemScope> fromStrings(Set<String> scope) { @@ -154,7 +154,7 @@ public class DefaultSystemScopeService implements SystemScopeService { } /* (non-Javadoc) - * @see org.mitre.oauth2.service.SystemScopeService#toStrings(java.util.Set) + * @see cz.muni.ics.oauth2.service.SystemScopeService#toStrings(java.util.Set) */ @Override public Set<String> toStrings(Set<SystemScope> scope) { @@ -166,7 +166,7 @@ public class DefaultSystemScopeService implements SystemScopeService { } /* (non-Javadoc) - * @see org.mitre.oauth2.service.SystemScopeService#scopesMatch(java.util.Set, java.util.Set) + * @see cz.muni.ics.oauth2.service.SystemScopeService#scopesMatch(java.util.Set, java.util.Set) */ @Override public boolean scopesMatch(Set<String> expected, Set<String> actual) { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/ServiceUtils.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/ServiceUtils.java similarity index 87% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/ServiceUtils.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/ServiceUtils.java index 4940c77e8..c8b047fdb 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/ServiceUtils.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/ServiceUtils.java @@ -1,7 +1,7 @@ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/UriEncodedClientUserDetailsService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/UriEncodedClientUserDetailsService.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/UriEncodedClientUserDetailsService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/UriEncodedClientUserDetailsService.java index 8baab7d71..dfd8dcb74 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/UriEncodedClientUserDetailsService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/UriEncodedClientUserDetailsService.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; import java.io.UnsupportedEncodingException; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/token/ChainedTokenGranter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/ChainedTokenGranter.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/oauth2/token/ChainedTokenGranter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/ChainedTokenGranter.java index c53596f26..8b622b70d 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/token/ChainedTokenGranter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/ChainedTokenGranter.java @@ -18,14 +18,14 @@ /** * */ -package org.mitre.oauth2.token; +package cz.muni.ics.oauth2.token; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; import java.util.HashSet; import java.util.Set; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.OAuth2TokenEntityService; +import cz.muni.ics.oauth2.service.OAuth2TokenEntityService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.AuthenticationException; import org.springframework.security.oauth2.common.exceptions.InvalidScopeException; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/token/DeviceTokenGranter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/DeviceTokenGranter.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/oauth2/token/DeviceTokenGranter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/DeviceTokenGranter.java index f7e185e53..63cfc3014 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/token/DeviceTokenGranter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/DeviceTokenGranter.java @@ -14,15 +14,15 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.token; +package cz.muni.ics.oauth2.token; import java.util.Date; -import org.mitre.oauth2.exception.AuthorizationPendingException; -import org.mitre.oauth2.exception.DeviceCodeExpiredException; -import org.mitre.oauth2.model.DeviceCode; -import org.mitre.oauth2.service.DeviceCodeService; -import org.mitre.oauth2.web.DeviceEndpoint; +import cz.muni.ics.oauth2.exception.AuthorizationPendingException; +import cz.muni.ics.oauth2.exception.DeviceCodeExpiredException; +import cz.muni.ics.oauth2.model.DeviceCode; +import cz.muni.ics.oauth2.service.DeviceCodeService; +import cz.muni.ics.oauth2.web.DeviceEndpoint; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; import org.springframework.security.oauth2.provider.ClientDetails; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/token/JWTAssertionTokenGranter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/JWTAssertionTokenGranter.java similarity index 90% rename from openid-connect-server/src/main/java/org/mitre/oauth2/token/JWTAssertionTokenGranter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/JWTAssertionTokenGranter.java index 02217fc48..f5ae867a2 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/token/JWTAssertionTokenGranter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/JWTAssertionTokenGranter.java @@ -18,15 +18,15 @@ /** * */ -package org.mitre.oauth2.token; +package cz.muni.ics.oauth2.token; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; import java.text.ParseException; -import org.mitre.jwt.assertion.AssertionValidator; -import org.mitre.oauth2.assertion.AssertionOAuth2RequestFactory; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.OAuth2TokenEntityService; -import org.mitre.openid.connect.assertion.JWTBearerAssertionAuthenticationToken; +import cz.muni.ics.jwt.assertion.AssertionValidator; +import cz.muni.ics.oauth2.assertion.AssertionOAuth2RequestFactory; +import cz.muni.ics.oauth2.service.OAuth2TokenEntityService; +import cz.muni.ics.openid.connect.assertion.JWTBearerAssertionAuthenticationToken; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.core.AuthenticationException; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/token/ScopeServiceAwareOAuth2RequestValidator.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/ScopeServiceAwareOAuth2RequestValidator.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/oauth2/token/ScopeServiceAwareOAuth2RequestValidator.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/ScopeServiceAwareOAuth2RequestValidator.java index 3896dfd3a..c9ac3dfb6 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/token/ScopeServiceAwareOAuth2RequestValidator.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/ScopeServiceAwareOAuth2RequestValidator.java @@ -18,11 +18,11 @@ /** * */ -package org.mitre.oauth2.token; +package cz.muni.ics.oauth2.token; import java.util.Set; -import org.mitre.oauth2.service.SystemScopeService; +import cz.muni.ics.oauth2.service.SystemScopeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.oauth2.common.exceptions.InvalidScopeException; import org.springframework.security.oauth2.provider.AuthorizationRequest; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/view/TokenApiView.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/view/TokenApiView.java similarity index 94% rename from openid-connect-server/src/main/java/org/mitre/oauth2/view/TokenApiView.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/view/TokenApiView.java index cd6eed06c..c49b1d816 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/view/TokenApiView.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/view/TokenApiView.java @@ -13,8 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.view; +package cz.muni.ics.oauth2.view; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonEntityView; import java.io.IOException; import java.io.Writer; import java.lang.reflect.Type; @@ -23,10 +27,6 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonEntityView; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/AuthenticationUtilities.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/AuthenticationUtilities.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/oauth2/web/AuthenticationUtilities.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/AuthenticationUtilities.java index ee56889cc..72572cbb2 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/AuthenticationUtilities.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/AuthenticationUtilities.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.web; +package cz.muni.ics.oauth2.web; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/CorsFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/CorsFilter.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/oauth2/web/CorsFilter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/CorsFilter.java index da2aa69d1..70a8f3003 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/CorsFilter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/CorsFilter.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.oauth2.web; +package cz.muni.ics.oauth2.web; import java.io.IOException; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/DeviceEndpoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/DeviceEndpoint.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/oauth2/web/DeviceEndpoint.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/DeviceEndpoint.java index 9c54c9f07..49fe7765d 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/DeviceEndpoint.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/DeviceEndpoint.java @@ -14,8 +14,18 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.web; +package cz.muni.ics.oauth2.web; +import cz.muni.ics.oauth2.exception.DeviceCodeCreationException; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.DeviceCode; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.oauth2.token.DeviceTokenGranter; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonEntityView; +import cz.muni.ics.openid.connect.view.JsonErrorView; import java.net.URI; import java.net.URISyntaxException; import java.util.Collection; @@ -24,23 +34,12 @@ import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; -import java.util.UUID; import javax.servlet.http.HttpSession; import org.apache.http.client.utils.URIBuilder; -import org.mitre.oauth2.exception.DeviceCodeCreationException; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.DeviceCode; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.DeviceCodeService; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.oauth2.token.DeviceTokenGranter; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonEntityView; -import org.mitre.openid.connect.view.JsonErrorView; +import cz.muni.ics.oauth2.service.DeviceCodeService; +import cz.muni.ics.oauth2.service.SystemScopeService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -50,7 +49,6 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.common.exceptions.InvalidClientException; import org.springframework.security.oauth2.common.util.OAuth2Utils; -import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; import org.springframework.security.oauth2.provider.AuthorizationRequest; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.OAuth2Request; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/IntrospectionEndpoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/IntrospectionEndpoint.java similarity index 88% rename from openid-connect-server/src/main/java/org/mitre/oauth2/web/IntrospectionEndpoint.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/IntrospectionEndpoint.java index 7725a5403..4b0be841a 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/IntrospectionEndpoint.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/IntrospectionEndpoint.java @@ -15,28 +15,26 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.web; - -import static org.mitre.oauth2.web.AuthenticationUtilities.ensureOAuthScope; +package cz.muni.ics.oauth2.web; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.service.UserInfoService; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonEntityView; +import cz.muni.ics.uma.model.ResourceSet; +import cz.muni.ics.uma.service.ResourceSetService; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.IntrospectionResultAssembler; -import org.mitre.oauth2.service.OAuth2TokenEntityService; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.service.UserInfoService; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonEntityView; -import org.mitre.uma.model.ResourceSet; -import org.mitre.uma.service.ResourceSetService; +import cz.muni.ics.oauth2.service.IntrospectionResultAssembler; +import cz.muni.ics.oauth2.service.OAuth2TokenEntityService; +import cz.muni.ics.oauth2.service.SystemScopeService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -98,7 +96,7 @@ public class IntrospectionEndpoint { if (auth instanceof OAuth2Authentication) { // the client authenticated with OAuth, do our UMA checks - ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE); + AuthenticationUtilities.ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE); // get out the client that was issued the access token (not the token being introspected) OAuth2Authentication o2a = (OAuth2Authentication) auth; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/OAuth2ExceptionHandler.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/OAuth2ExceptionHandler.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/oauth2/web/OAuth2ExceptionHandler.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/OAuth2ExceptionHandler.java index 2a361cffd..75ed7d911 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/OAuth2ExceptionHandler.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/OAuth2ExceptionHandler.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.web; +package cz.muni.ics.oauth2.web; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/OAuthConfirmationController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/OAuthConfirmationController.java similarity index 88% rename from openid-connect-server/src/main/java/org/mitre/oauth2/web/OAuthConfirmationController.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/OAuthConfirmationController.java index 3d7a7b734..926b6de0c 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/OAuthConfirmationController.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/OAuthConfirmationController.java @@ -18,22 +18,23 @@ /** * */ -package org.mitre.oauth2.web; +package cz.muni.ics.oauth2.web; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.Sets; import com.google.gson.JsonObject; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.request.ConnectRequestParameters; +import cz.muni.ics.openid.connect.service.ScopeClaimTranslationService; +import cz.muni.ics.openid.connect.service.UserInfoService; +import cz.muni.ics.openid.connect.view.HttpCodeView; import org.apache.http.client.utils.URIBuilder; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.service.ScopeClaimTranslationService; -import org.mitre.openid.connect.service.UserInfoService; -import org.mitre.openid.connect.view.HttpCodeView; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -43,7 +44,6 @@ import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; import org.springframework.security.oauth2.provider.AuthorizationRequest; import org.springframework.security.oauth2.provider.endpoint.RedirectResolver; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.SessionAttributes; @@ -55,9 +55,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT; -import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_SEPARATOR; - /** * @author jricher * @@ -102,8 +99,8 @@ public class OAuthConfirmationController { AuthorizationRequest authRequest = (AuthorizationRequest) model.get("authorizationRequest"); // Check the "prompt" parameter to see if we need to do special processing - String prompt = (String)authRequest.getExtensions().get(PROMPT); - List<String> prompts = Splitter.on(PROMPT_SEPARATOR).splitToList(Strings.nullToEmpty(prompt)); + String prompt = (String)authRequest.getExtensions().get(ConnectRequestParameters.PROMPT); + List<String> prompts = Splitter.on(ConnectRequestParameters.PROMPT_SEPARATOR).splitToList(Strings.nullToEmpty(prompt)); ClientDetailsEntity client = null; try { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/RevocationEndpoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/RevocationEndpoint.java similarity index 91% rename from openid-connect-server/src/main/java/org/mitre/oauth2/web/RevocationEndpoint.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/RevocationEndpoint.java index dd202fe9f..2da5409a9 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/RevocationEndpoint.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/RevocationEndpoint.java @@ -15,17 +15,17 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.web; +package cz.muni.ics.oauth2.web; -import static org.mitre.oauth2.web.AuthenticationUtilities.ensureOAuthScope; +import static cz.muni.ics.oauth2.web.AuthenticationUtilities.ensureOAuthScope; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.OAuth2TokenEntityService; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.view.HttpCodeView; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.oauth2.service.OAuth2TokenEntityService; +import cz.muni.ics.oauth2.service.SystemScopeService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/ScopeAPI.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/ScopeAPI.java similarity index 94% rename from openid-connect-server/src/main/java/org/mitre/oauth2/web/ScopeAPI.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/ScopeAPI.java index 5aa6d2a3b..0dacad5de 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/ScopeAPI.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/ScopeAPI.java @@ -18,16 +18,16 @@ /** * */ -package org.mitre.oauth2.web; +package cz.muni.ics.oauth2.web; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonEntityView; +import cz.muni.ics.openid.connect.view.JsonErrorView; +import cz.muni.ics.openid.connect.web.RootController; import java.util.Set; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonEntityView; -import org.mitre.openid.connect.view.JsonErrorView; -import org.mitre.openid.connect.web.RootController; +import cz.muni.ics.oauth2.service.SystemScopeService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/TokenAPI.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/TokenAPI.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/oauth2/web/TokenAPI.java rename to perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/TokenAPI.java index 73fa472b4..b1691818d 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/TokenAPI.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/TokenAPI.java @@ -15,23 +15,23 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.web; +package cz.muni.ics.oauth2.web; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.oauth2.view.TokenApiView; +import cz.muni.ics.openid.connect.service.OIDCTokenService; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonEntityView; +import cz.muni.ics.openid.connect.view.JsonErrorView; +import cz.muni.ics.openid.connect.web.RootController; import java.security.Principal; import java.util.List; import java.util.Set; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.OAuth2TokenEntityService; -import org.mitre.oauth2.view.TokenApiView; -import org.mitre.openid.connect.service.OIDCTokenService; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonEntityView; -import org.mitre.openid.connect.view.JsonErrorView; -import org.mitre.openid.connect.web.RootController; +import cz.muni.ics.oauth2.service.OAuth2TokenEntityService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/BeanUtil.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/BeanUtil.java new file mode 100644 index 000000000..b281b21ab --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/BeanUtil.java @@ -0,0 +1,34 @@ +package cz.muni.ics.oidc; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Service; + +/** + * Utility class for working with beans. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@Service +public class BeanUtil implements ApplicationContextAware { + + private ApplicationContext context; + + public <T> T getBean(String name, Class<T> beanClass) { + return context.getBean(name, beanClass); + } + + public <T> T getBean(Class<T> beanClass) { + return context.getBean(beanClass); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + context = applicationContext; + } + + public ApplicationContext getContext() { + return context; + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/ExecutionTimeLoggingAspect.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/ExecutionTimeLoggingAspect.java new file mode 100644 index 000000000..1f5dd5213 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/ExecutionTimeLoggingAspect.java @@ -0,0 +1,21 @@ +package cz.muni.ics.oidc.aop; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Aspect +@Component +public class ExecutionTimeLoggingAspect { + + public static final Logger log = LoggerFactory.getLogger(ExecutionTimeLoggingAspect.class); + + @Around("@annotation(LogTimes) && execution(* cz.muni.ics.oidc.server.connectors..* (..))") + public Object logExecutionTimeForConnectorsWithParams(ProceedingJoinPoint pjp) throws Throwable { + return LoggingUtils.logExecutionTimes(log, pjp); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/LogTimes.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/LogTimes.java new file mode 100644 index 000000000..83b4c860e --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/LogTimes.java @@ -0,0 +1,11 @@ +package cz.muni.ics.oidc.aop; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface LogTimes { +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/LoggingUtils.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/LoggingUtils.java new file mode 100644 index 000000000..540871a4d --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/LoggingUtils.java @@ -0,0 +1,72 @@ +package cz.muni.ics.oidc.aop; + +import java.sql.Timestamp; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.slf4j.Logger; + +/** + * Utility class that takes care of the logging for AOP. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class LoggingUtils { + + /** + * Log at TRACE level end of method. + * @param log Logger object. + * @param jp Join point. + * @return Value returned by the methods. + */ + public static Object logExecutionEnd(Logger log, JoinPoint jp, Object result) { + String className = jp.getTarget().getClass().getName(); + String methodName = jp.getSignature().getName(); + Object[] args = jp.getArgs(); + log.trace("{}.{}({}) returns: {}", className, methodName, args.length > 0 ? args : "", result); + return result; + } + + /** + * Log at TRACE level end of method. + * @param log Logger object. + * @param jp Join point. + * @throws Throwable thrown exception by the method execution. + */ + public static void logExecutionException(Logger log, JoinPoint jp, Throwable t) throws Throwable { + String className = jp.getTarget().getClass().getName(); + String methodName = jp.getSignature().getName(); + Object[] args = jp.getArgs(); + log.warn("{}.{}({}) has thrown {}", className, methodName, args.length > 0 ? args : "", t.getClass(), t); + throw t; + } + + /** + * Log at TRACE level times of start and end of method execution. + * @param log Logger object. + * @param pjp proceeding join point. + * @return Value returned by the methods. + * @throws Throwable throw exception by the method execution. + */ + public static Object logExecutionTimes(Logger log, ProceedingJoinPoint pjp) throws Throwable { + String className = pjp.getTarget().getClass().getName(); + String methodName = pjp.getSignature().getName(); + Object[] args = pjp.getArgs(); + long start = System.currentTimeMillis(); + + log.trace("Execution of {}.{}({}) started at {}", + className, methodName, args.length > 0 ? args : "", new Timestamp(start)); + try { + Object result = pjp.proceed(); + long finish = System.currentTimeMillis(); + log.trace("Execution of {}.{}({}) finished successfully at {}, execution took {}ms", + className, methodName, args.length > 0 ? args : "", new Timestamp(finish), finish - start); + return result; + } catch (Throwable e) { + long finish = System.currentTimeMillis(); + log.trace("Execution of {}.{}({}) finished by exception being thrown at {}, execution took {}ms", + className, methodName, args.length > 0 ? args : "", new Timestamp(finish), finish - start); + throw e; + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/MapperLoggingAspect.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/MapperLoggingAspect.java new file mode 100644 index 000000000..5e66af3b4 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/MapperLoggingAspect.java @@ -0,0 +1,27 @@ +package cz.muni.ics.oidc.aop; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Aspect +@Component +public class MapperLoggingAspect { + + public static final Logger log = LoggerFactory.getLogger(MapperLoggingAspect.class); + + @AfterReturning(value = "execution(* cz.muni.ics.oidc.models.mappers..* (..))", returning = "result") + public Object logAroundMethodWithParams(JoinPoint jp, Object result) { + return LoggingUtils.logExecutionEnd(log, jp, result); + } + + @AfterThrowing(value = "execution(* cz.muni.ics.oidc.models.mappers..* (..))", throwing = "t") + public void logAroundMethodWithParams(JoinPoint jp, Throwable t) throws Throwable { + LoggingUtils.logExecutionException(log, jp, t); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/ServerLoggingAspect.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/ServerLoggingAspect.java new file mode 100644 index 000000000..2841dbbab --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/ServerLoggingAspect.java @@ -0,0 +1,27 @@ +package cz.muni.ics.oidc.aop; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Aspect +@Component +public class ServerLoggingAspect { + + public static final Logger log = LoggerFactory.getLogger(ServerLoggingAspect.class); + + @AfterReturning(value = "execution(* cz.muni.ics.oidc.server..* (..))", returning = "result") + public Object logAroundMethodWithParams(JoinPoint jp, Object result) { + return LoggingUtils.logExecutionEnd(log, jp, result); + } + + @AfterThrowing(value = "execution(* cz.muni.ics.oidc.server..* (..))", throwing = "t") + public void logAroundMethodWithParams(JoinPoint jp, Throwable t) throws Throwable { + LoggingUtils.logExecutionException(log, jp, t); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/WebLoggingAspect.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/WebLoggingAspect.java new file mode 100644 index 000000000..b021e7611 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/aop/WebLoggingAspect.java @@ -0,0 +1,27 @@ +package cz.muni.ics.oidc.aop; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Aspect +@Component +public class WebLoggingAspect { + + public static final Logger log = LoggerFactory.getLogger(WebLoggingAspect.class); + + @AfterReturning(value = "execution(* cz.muni.ics.oidc.web..* (..))", returning = "result") + public Object logAroundMethodWithParams(JoinPoint jp, Object result) { + return LoggingUtils.logExecutionEnd(log, jp, result); + } + + @AfterThrowing(value = "execution(* cz.muni.ics.oidc.web..* (..))", throwing = "t") + public void logAroundMethodWithParams(JoinPoint jp, Throwable t) throws Throwable { + LoggingUtils.logExecutionException(log, jp, t); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/exceptions/ConfigurationException.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/exceptions/ConfigurationException.java new file mode 100644 index 000000000..995e4bcfe --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/exceptions/ConfigurationException.java @@ -0,0 +1,25 @@ +package cz.muni.ics.oidc.exceptions; + +public class ConfigurationException extends Exception { + + public ConfigurationException() { + super(); + } + + public ConfigurationException(String s) { + super(s); + } + + public ConfigurationException(String s, Throwable throwable) { + super(s, throwable); + } + + public ConfigurationException(Throwable throwable) { + super(throwable); + } + + protected ConfigurationException(String s, Throwable throwable, boolean b, boolean b1) { + super(s, throwable, b, b1); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/exceptions/InconvertibleValueException.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/exceptions/InconvertibleValueException.java new file mode 100644 index 000000000..25386c38e --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/exceptions/InconvertibleValueException.java @@ -0,0 +1,24 @@ +package cz.muni.ics.oidc.exceptions; + +public class InconvertibleValueException extends RuntimeException { + + public InconvertibleValueException() { + super(); + } + + public InconvertibleValueException(String s) { + super(s); + } + + public InconvertibleValueException(String s, Throwable throwable) { + super(s, throwable); + } + + public InconvertibleValueException(Throwable throwable) { + super(throwable); + } + + protected InconvertibleValueException(String s, Throwable throwable, boolean b, boolean b1) { + super(s, throwable, b, b1); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/exceptions/MissingFieldException.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/exceptions/MissingFieldException.java new file mode 100644 index 000000000..a1e7b340c --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/exceptions/MissingFieldException.java @@ -0,0 +1,23 @@ +package cz.muni.ics.oidc.exceptions; + +public class MissingFieldException extends RuntimeException { + public MissingFieldException() { + super(); + } + + public MissingFieldException(String s) { + super(s); + } + + public MissingFieldException(String s, Throwable throwable) { + super(s, throwable); + } + + public MissingFieldException(Throwable throwable) { + super(throwable); + } + + protected MissingFieldException(String s, Throwable throwable, boolean b, boolean b1) { + super(s, throwable, b, b1); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/AttributeMapping.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/AttributeMapping.java new file mode 100644 index 000000000..632efa9d1 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/AttributeMapping.java @@ -0,0 +1,141 @@ +package cz.muni.ics.oidc.models; + +import com.google.common.base.Strings; +import cz.muni.ics.oidc.models.enums.PerunAttrValueType; +import java.util.Objects; + +/** + * Attribute mapping model. Provides mapping of attribute with an internal name to names specific for interfaces + * (i.e. LDAP, RPC, ...) + * + * Configuration (replace [attrName] with the actual name of the attribute): + * <ul> + * <li><b>[attrName].mapping.ldap</b> - name of attribute in LDAP</li> + * <li><b>[attrName].mapping.rpc</b> - name of attribute in LDAP</li> + * <li><b>[attrName].mapping.type</b> - [STRING|INTEGER|BOOLEAN|ARRAY|MAP_JSON|MAP_KEY_VALUE] + * - type of attribute value, defaults to STRING</li> + * <li><b>[attrName].mapping.separator</b> - separator of keys ands values if type equals to MAP_KEY_VALUE, defaults to '='</li> + * </ul> + * @see cz.muni.ics.oidc.server.AttributeMappingsService for attrName configurations + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class AttributeMapping { + + private String identifier; + private String rpcName; + private String ldapName; + private PerunAttrValueType attrType; + private String separator; + + public AttributeMapping() { + } + + public AttributeMapping(String identifier, String rpcName, String ldapName, String type) { + super(); + this.setIdentifier(identifier); + this.setRpcName(rpcName); + this.setLdapName(ldapName); + this.setAttrType(type); + this.setSeparator(""); + } + + public AttributeMapping(String identifier, String rpcName, String ldapName, String type, String separator) { + super(); + this.setIdentifier(identifier); + this.setRpcName(rpcName); + this.setLdapName(ldapName); + this.setAttrType(type); + this.setSeparator(separator); + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + if (Strings.isNullOrEmpty(identifier)) { + throw new IllegalArgumentException("identifier cannot be null nor empty"); + } + + this.identifier = identifier; + } + + public String getRpcName() { + return rpcName; + } + + public void setRpcName(String rpcName) { + if (Strings.isNullOrEmpty(rpcName)) { + throw new IllegalArgumentException("rpcName cannot be null nor empty"); + } + + this.rpcName = rpcName; + } + + public String getLdapName() { + return ldapName; + } + + public void setLdapName(String ldapName) { + this.ldapName = ldapName; + } + + public PerunAttrValueType getAttrType() { + return attrType; + } + + public void setAttrType(String typeStr) { + PerunAttrValueType type = PerunAttrValueType.parse(typeStr); + this.setAttrType(type); + } + + public void setAttrType(PerunAttrValueType attrType) { + if (attrType == null) { + throw new IllegalArgumentException("Type cannot be null"); + } + this.attrType = attrType; + } + + public String getSeparator() { + return this.separator; + } + + public void setSeparator(String separator) { + if (separator == null || separator.trim().isEmpty()) { + separator = "="; + } + this.separator = separator; + } + + @Override + public String toString() { + String str = "AttributeMapping{" + + "identifier='" + identifier + '\'' + + ", rpcName='" + rpcName + '\'' + + ", ldapName='" + ldapName + '\'' + + ", attrType='" + attrType; + if (PerunAttrValueType.MAP_KEY_VALUE.equals(attrType)) { + str += "', separator='" + separator; + } + str += "'}"; + + return str; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AttributeMapping that = (AttributeMapping) o; + return Objects.equals(identifier, that.identifier) && + Objects.equals(rpcName, that.rpcName) && + Objects.equals(ldapName, that.ldapName); + } + + @Override + public int hashCode() { + return Objects.hash(identifier, rpcName, ldapName); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Aup.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Aup.java new file mode 100644 index 000000000..4b8f7deee --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Aup.java @@ -0,0 +1,127 @@ +package cz.muni.ics.oidc.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.base.Strings; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Objects; + +/** + * AUP object model. + * + * @author Dominik Baranek <baranek@ics.muni.cz> + */ +public class Aup { + + public static final String SIGNED_ON = "signed_on"; + + private static final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + private String version; + private String date; + private String link; + private String text; + + @JsonProperty(SIGNED_ON) + private String signedOn = null; + + public Aup() { + } + + public Aup(String version, String date, String link, String text, String signedOn) { + this.setVersion(version); + this.setDate(date); + this.setLink(link); + this.setText(text); + this.setSignedOn(signedOn); + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + if (Strings.isNullOrEmpty(version)) { + throw new IllegalArgumentException("version cannot be null or empty"); + } + + this.version = version; + } + + public String getDate() { + return date; + } + + @JsonIgnore + public LocalDate getDateAsLocalDate() { + return LocalDate.parse(date, format); + } + + public void setDate(String date) { + if (Strings.isNullOrEmpty(date)) { + throw new IllegalArgumentException("date cannot be null or empty"); + } + + this.date = date; + } + + public String getLink() { + return link; + } + + public void setLink(String link) { + if (Strings.isNullOrEmpty(link)) { + throw new IllegalArgumentException("link cannot be null or empty"); + } + + this.link = link; + } + + public String getText() { + return text; + } + + public void setText(String text) { + if (text == null) { + throw new IllegalArgumentException("version cannot be null"); + } + + this.text = text; + } + + public String getSignedOn() { + return signedOn; + } + + public void setSignedOn(String signedOn) { + this.signedOn = signedOn; + } + + @Override + public String toString() { + return "Aup{" + + "version='" + version + '\'' + + ", date='" + date + '\'' + + ", link='" + link + '\'' + + ", text='" + text + '\'' + + ", signedOn='" + signedOn + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Aup aup = (Aup) o; + return Objects.equals(version, aup.version) && + Objects.equals(date, aup.date) && + Objects.equals(link, aup.link) && + Objects.equals(text, aup.text); + } + + @Override + public int hashCode() { + return Objects.hash(version, date, link, text); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/ExtSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/ExtSource.java new file mode 100644 index 000000000..1b7fe7bba --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/ExtSource.java @@ -0,0 +1,72 @@ +package cz.muni.ics.oidc.models; + +import com.google.common.base.Strings; +import java.util.Objects; + +/** + * Model for ExtSource + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class ExtSource extends Model { + + private String name; + private String type; + + public ExtSource() { + } + + public ExtSource(Long id, String name, String type) { + super(id); + this.setName(name); + this.setType(type); + } + + public String getName() { + return name; + } + + public void setName(String name) { + if (Strings.isNullOrEmpty(name)) { + throw new IllegalArgumentException("name cannot be null nor empty"); + } + + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + if (Strings.isNullOrEmpty(type)) { + throw new IllegalArgumentException("type cannot be null nor empty"); + } + + this.type = type; + } + + @Override + public String toString() { + return "ExtSource{" + + "id=" + getId() + + ", name='" + name + '\'' + + ", type='" + type + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + ExtSource extSource = (ExtSource) o; + return Objects.equals(name, extSource.name) && + Objects.equals(type, extSource.type); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), name, type); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Facility.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Facility.java new file mode 100644 index 000000000..39bc6a8c6 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Facility.java @@ -0,0 +1,68 @@ +package cz.muni.ics.oidc.models; + +import com.google.common.base.Strings; +import java.util.Objects; + +/** + * Facility object model. + * + * @author Peter Jancus <jancus@ics.muni.cz> + */ +public class Facility extends Model { + + private String name; + private String description; + + public Facility() { + } + + public Facility(Long id, String name, String description) { + super(id); + this.name = name; + this.description = description; + } + + public String getName() { + return name; + } + + public void setName(String name) { + if (Strings.isNullOrEmpty(name)) { + throw new IllegalArgumentException("name cannot be null nor empty"); + } + + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "Facility{" + + "id=" + getId() + + ", name='" + name + '\'' + + ", description='" + description + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + Facility facility = (Facility) o; + return Objects.equals(name, facility.name) && + Objects.equals(description, facility.description); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), name, description); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Group.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Group.java new file mode 100644 index 000000000..a70a7b630 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Group.java @@ -0,0 +1,169 @@ +package cz.muni.ics.oidc.models; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.base.Strings; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Group object model. + * + * @author Peter Jancus <jancus@ics.muni.cz> + */ +public class Group extends Model { + + private Long parentGroupId; + private String name; + private String description; + private String uniqueGroupName; // voShortName + ":" + group name + private String uuid; + private Long voId; + + private Map<String, JsonNode> attributes = new LinkedHashMap<>(); + + public Group() { + } + + public Group(Long id, Long parentGroupId, String name, String description, String uniqueGroupName, String uuid, Long voId) { + super(id); + this.setParentGroupId(parentGroupId); + this.setName(name); + this.setDescription(description); + this.setUniqueGroupName(uniqueGroupName); + this.setUuid(uuid); + this.setVoId(voId); + } + + public Long getParentGroupId() { + return parentGroupId; + } + + public void setParentGroupId(Long parentGroupId) { + this.parentGroupId = parentGroupId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + if (Strings.isNullOrEmpty(name)) { + throw new IllegalArgumentException("name cannot be null nor empty"); + } + + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + if (Strings.isNullOrEmpty(description)) { + throw new IllegalArgumentException("description cannot be null nor empty"); + } + + this.description = description; + } + + public void setUniqueGroupName(String uniqueGroupName) { + this.uniqueGroupName = uniqueGroupName; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public Long getVoId() { + return voId; + } + + public void setVoId(Long voId) { + if (voId == null) { + throw new IllegalArgumentException("voId cannot be null"); + } + + this.voId = voId; + } + + public Map<String, JsonNode> getAttributes() { + return attributes; + } + + public void setAttributes(Map<String, JsonNode> attributes) { + this.attributes = attributes; + } + + /** + * Gets identifier voShortName:group.name usable for groupNames in AARC format. + */ + public String getUniqueGroupName() { + return uniqueGroupName; + } + + /** + * Gets attribute by urn name + * + * @param attributeName urn name of attribute + * @return attribute + */ + public JsonNode getAttributeByUrnName(String attributeName) { + if (attributes == null || !attributes.containsKey(attributeName)) { + return null; + } + + return attributes.get(attributeName); + } + + /** + * Gets attribute by friendly name + * + * @param attributeName attribute name + * @param attributeUrnPrefix urn prefix of attribute + * @return attribute + */ + public JsonNode getAttributeByFriendlyName(String attributeName, String attributeUrnPrefix) { + String key = attributeUrnPrefix + ":" + attributeName; + + if (attributes == null || !attributes.containsKey(key)) { + return null; + } + + return attributes.get(key); + } + + @Override + public String toString() { + return "Group{" + + "id=" + getId() + + ", name='" + name + '\'' + + ", uniqueGroupName='" + uniqueGroupName + '\'' + + ", description='" + description + '\'' + + ", parentGroupId=" + parentGroupId + + ", voId=" + voId + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + Group group = (Group) o; + return Objects.equals(parentGroupId, group.parentGroupId) && + Objects.equals(name, group.name) && + Objects.equals(description, group.description) && + Objects.equals(uniqueGroupName, group.uniqueGroupName) && + Objects.equals(voId, group.voId); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), parentGroupId, name, description, uniqueGroupName, voId); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Member.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Member.java new file mode 100644 index 000000000..f928bde6c --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Member.java @@ -0,0 +1,88 @@ +package cz.muni.ics.oidc.models; + +import cz.muni.ics.oidc.models.enums.MemberStatus; +import java.util.Objects; + +/** + * Member object model. + * + * @author Peter Jancus <jancus@ics.muni.cz> + */ +public class Member extends Model { + + private Long userId; + private Long voId; + private MemberStatus status; + + public Member() { + } + + public Member(Long id, Long userId, Long voId, MemberStatus status) { + super(id); + this.setUserId(userId); + this.setVoId(voId); + this.setStatus(status); + } + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + if (userId == null) { + throw new IllegalArgumentException("userId cannot be null"); + } + + this.userId = userId; + } + + public Long getVoId() { + return voId; + } + + public void setVoId(Long voId) { + if (voId == null) { + throw new IllegalArgumentException("voId cannot be null"); + } + + this.voId = voId; + } + + public MemberStatus getStatus() { + return status; + } + + public void setStatus(MemberStatus status) { + if (status == null) { + throw new IllegalArgumentException("status cannot be null nor empty"); + } + + this.status = status; + } + + @Override + public String toString() { + return "Member{" + + "id=" + getId() + + ", userId=" + userId + + ", voId=" + voId + + ", status='" + status + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + Member member = (Member) o; + return Objects.equals(userId, member.userId) && + Objects.equals(voId, member.voId) && + Objects.equals(status, member.status); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), userId, voId, status); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Model.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Model.java new file mode 100644 index 000000000..7dabd3902 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Model.java @@ -0,0 +1,46 @@ +package cz.muni.ics.oidc.models; + +/** + * Basic model with ID. Should be extended by another specific models with specific variables. + * + * @author Peter Jancus <jancus@ics.muni.cz> + */ +public abstract class Model { + + private Long id; + + public Model() { + } + + public Model(Long id) { + super(); + this.setId(id); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + if (id == null) { + throw new IllegalArgumentException("id cannot be null"); + } + + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Model)) return false; + + Model model = (Model) o; + + return getId() != null ? getId().equals(model.getId()) : model.getId() == null; + } + + @Override + public int hashCode() { + return getId() != null ? getId().hashCode() : 0; + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunAttribute.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunAttribute.java new file mode 100644 index 000000000..4e42f9479 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunAttribute.java @@ -0,0 +1,194 @@ +package cz.muni.ics.oidc.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.springframework.util.StringUtils; + +/** + * Perun Attribute model + * + * @author Dominik Frantisek Bucik <bucik@.ics.muni.cz> + * @author Ondrej Ernst <ondra.ernst@gmail.com> + */ +public class PerunAttribute extends PerunAttributeValueAwareModel { + + private static final String BEAN_NAME = "Attribute"; + + private Long id; + private String friendlyName; + private String namespace; + private String description; + private String displayName; + private boolean writable; + private boolean unique; + private String entity; + private String baseFriendlyName; + private String friendlyNameParameter; + private String valueCreatedAt; + private String valueModifiedAt; + + public PerunAttribute(Long id, String friendlyName, String namespace, String description, String type, + String displayName, boolean writable, boolean unique, String entity, String baseFriendlyName, + String friendlyNameParameter, JsonNode value, String valueCreatedAt, String valueModifiedAt) + { + super(type, value); + this.setId(id); + this.setFriendlyName(friendlyName); + this.setNamespace(namespace); + this.setDescription(description); + this.setType(type); + this.setDisplayName(displayName); + this.setWritable(writable); + this.setUnique(unique); + this.setEntity(entity); + this.setBaseFriendlyName(baseFriendlyName); + this.setFriendlyNameParameter(friendlyNameParameter); + this.setValue(type, value); + this.setValueCreatedAt(valueCreatedAt); + this.setValueModifiedAt(valueModifiedAt); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFriendlyName() { + return friendlyName; + } + + public void setFriendlyName(String friendlyName) { + if (!StringUtils.hasText(friendlyName)) { + throw new IllegalArgumentException("friendlyName cannot be empty"); + } + + this.friendlyName = friendlyName; + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + if (!StringUtils.hasText(namespace)) { + throw new IllegalArgumentException("namespace cannot be empty"); + } + + this.namespace = namespace; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + if (!StringUtils.hasText(displayName)) { + throw new IllegalArgumentException("displayName cannot be empty"); + } + + this.displayName = displayName; + } + + public boolean isWritable() { + return writable; + } + + public void setWritable(boolean writable) { + this.writable = writable; + } + + public boolean isUnique() { + return unique; + } + + public void setUnique(boolean unique) { + this.unique = unique; + } + + public String getEntity() { + return entity; + } + + public void setEntity(String entity) { + if (!StringUtils.hasText(entity)) { + throw new IllegalArgumentException("entity cannot be empty"); + } + + this.entity = entity; + } + + public String getBaseFriendlyName() { + return baseFriendlyName; + } + + public void setBaseFriendlyName(String baseFriendlyName) { + this.baseFriendlyName = baseFriendlyName; + } + + public String getFriendlyNameParameter() { + return friendlyNameParameter; + } + + public void setFriendlyNameParameter(String friendlyNameParameter) { + this.friendlyNameParameter = friendlyNameParameter; + } + + public String getValueCreatedAt() { + return valueCreatedAt; + } + + public void setValueCreatedAt(String valueCreatedAt) { + this.valueCreatedAt = valueCreatedAt; + } + + public String getValueModifiedAt() { + return valueModifiedAt; + } + + public void setValueModifiedAt(String valueModifiedAt) { + this.valueModifiedAt = valueModifiedAt; + } + + @JsonIgnore + public String getUrn() { + return this.namespace + ':' + this.friendlyName; + } + + public ObjectNode toJson() { + ObjectNode node = JsonNodeFactory.instance.objectNode(); + + node.put("id", id); + node.put("friendlyName", friendlyName); + node.put("namespace", namespace); + node.put("type", super.getType()); + node.put("displayName", displayName); + node.put("writable", writable); + node.put("unique", unique); + node.put("entity", entity); + node.put("beanName", BEAN_NAME); + node.put("baseFriendlyName", baseFriendlyName); + node.put("friendlyName", friendlyName); + node.put("friendlyNameParameter", friendlyNameParameter); + node.set("value", this.valueAsJson()); + + return node; + } + + public PerunAttributeValue toPerunAttributeValue() { + return new PerunAttributeValue(this.getUrn(), super.getType(), this.valueAsJson()); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunAttributeValue.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunAttributeValue.java new file mode 100644 index 000000000..46af02058 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunAttributeValue.java @@ -0,0 +1,48 @@ +package cz.muni.ics.oidc.models; + +import com.fasterxml.jackson.databind.JsonNode; +import java.util.Objects; + +/** + * Model representing value of attribute from Perun. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class PerunAttributeValue extends PerunAttributeValueAwareModel { + + private String attrName; + + public PerunAttributeValue(String attrName, String type, JsonNode value) { + super(type, value); + this.setAttrName(attrName); + } + + public String getAttrName() { + return attrName; + } + + public void setAttrName(String attrName) { + this.attrName = attrName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PerunAttributeValue that = (PerunAttributeValue) o; + return super.equals(that) && Objects.equals(attrName, that.attrName); + } + + @Override + public int hashCode() { + return Objects.hash(getType(), valueAsJson(), attrName); + } + + @Override + public String toString() { + return "PerunAttributeValue{" + + "attrName='" + attrName + '\'' + + '}'; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunAttributeValueAwareModel.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunAttributeValueAwareModel.java new file mode 100644 index 000000000..73f6eef0a --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunAttributeValueAwareModel.java @@ -0,0 +1,164 @@ +package cz.muni.ics.oidc.models; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.BooleanNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.NumericNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; +import cz.muni.ics.oidc.exceptions.InconvertibleValueException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.springframework.util.StringUtils; + +/** + * Interface should be implemented by all models that represent value of an Attribute from Perun. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public abstract class PerunAttributeValueAwareModel { + + public final static String STRING_TYPE = "java.lang.String"; + public final static String INTEGER_TYPE = "java.lang.Integer"; + public final static String BOOLEAN_TYPE = "java.lang.Boolean"; + public final static String ARRAY_TYPE = "java.util.ArrayList"; + public final static String MAP_TYPE = "java.util.LinkedHashMap"; + public final static String LARGE_STRING_TYPE = "java.lang.LargeString"; + public final static String LARGE_ARRAY_LIST_TYPE = "java.util.LargeArrayList"; + + private String type; + private JsonNode value; + + public PerunAttributeValueAwareModel(String type, JsonNode value) { + this.setType(type); + this.setValue(type, value); + } + + public void setType(String type) { + if (!StringUtils.hasText(type)) { + throw new IllegalArgumentException("type can't be null or empty"); + } + + this.type = type; + } + + public String getType() { + return type; + } + + public void setValue(String type, JsonNode value) { + if (PerunAttributeValueAwareModel.isNullValue(value)) { + if (BOOLEAN_TYPE.equals(type)) { + value = JsonNodeFactory.instance.booleanNode(false); + } else if (ARRAY_TYPE.equals(type)) { + value = JsonNodeFactory.instance.arrayNode(); + } else if (MAP_TYPE.equals(type)) { + value = JsonNodeFactory.instance.objectNode(); + } else { + value = JsonNodeFactory.instance.nullNode(); + } + } + + this.value = value; + } + + public String valueAsString() { + if ((STRING_TYPE.equals(type) || LARGE_STRING_TYPE.equals(type))) { + if (PerunAttributeValueAwareModel.isNullValue(value)) { + return null; + } else if (value instanceof TextNode) { + return value.textValue(); + } + } + + return value.asText(); + } + + public Integer valueAsInteger() { + if (INTEGER_TYPE.equals(type)) { + if (PerunAttributeValueAwareModel.isNullValue(value)) { + return null; + } else if (value instanceof NumericNode) { + return value.intValue(); + } + } + + throw this.inconvertible(Long.class.getName()); + } + + public boolean valueAsBoolean() { + if (BOOLEAN_TYPE.equals(type)) { + if (value == null || value instanceof NullNode) { + return false; + } else if (value instanceof BooleanNode) { + return value.asBoolean(); + } + } + + throw this.inconvertible(Boolean.class.getName()); + } + + public List<String> valueAsList() { + List<String> arr = new ArrayList<>(); + if ((ARRAY_TYPE.equals(type) || LARGE_ARRAY_LIST_TYPE.equals(type))) { + if (PerunAttributeValueAwareModel.isNullValue(value)) { + return null; + } else if (value instanceof ArrayNode) { + ArrayNode arrJson = (ArrayNode) value; + arrJson.forEach(item -> arr.add(item.asText())); + } + } else { + arr.add(this.valueAsString()); + } + + return arr; + } + + public Map<String, String> valueAsMap() { + if (MAP_TYPE.equals(type)) { + if (PerunAttributeValueAwareModel.isNullValue(value)) { + return new HashMap<>(); + } else if (value instanceof ObjectNode) { + Map<String, String> res = new HashMap<>(); + ObjectNode objJson = (ObjectNode) value; + Iterator<String> it = objJson.fieldNames(); + while (it.hasNext()) { + String key = it.next(); + res.put(key, objJson.get(key).asText()); + } + return res; + } + } + + throw this.inconvertible(Map.class.getName()); + } + + public JsonNode valueAsJson() { + return this.value; + } + + public boolean isNullValue() { + return value == null || + value instanceof NullNode || + value.isNull() || + "null".equalsIgnoreCase(value.asText()); + } + + public static boolean isNullValue(JsonNode value) { + return value == null || + value instanceof NullNode || + value.isNull() || + "null".equalsIgnoreCase(value.asText()); + } + + private InconvertibleValueException inconvertible(String clazzName) { + return new InconvertibleValueException("Cannot convert value of attribute to " + clazzName + + " for object: " + this.toString()); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunUser.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunUser.java new file mode 100644 index 000000000..ffdd343d4 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/PerunUser.java @@ -0,0 +1,71 @@ +package cz.muni.ics.oidc.models; + +import com.google.common.base.Strings; +import java.io.Serializable; +import java.util.Objects; + +/** + * Represents user from Perun. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class PerunUser extends Model implements Serializable { + + private String firstName; + private String lastName; + + public PerunUser() { + } + + public PerunUser(long id, String firstName, String lastName) { + super(id); + this.setFirstName(firstName); + this.setLastName(lastName); + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + if (Strings.isNullOrEmpty(lastName)) { + throw new IllegalArgumentException("name can't be null or empty"); + } + + this.lastName = lastName; + } + + @Override + public String toString() { + return "PerunUser{" + + "id=" + getId() + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + PerunUser user = (PerunUser) o; + return Objects.equals(firstName, user.firstName) && + Objects.equals(lastName, user.lastName); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), firstName, lastName); + } + + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Resource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Resource.java new file mode 100644 index 000000000..b521e22cf --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Resource.java @@ -0,0 +1,121 @@ +package cz.muni.ics.oidc.models; + +import com.google.common.base.Strings; +import java.util.Objects; + +/** + * Resource object model. + * + * @author Peter Jancus <jancus@ics.muni.cz> + */ +public class Resource extends Model { + + private Long voId; + private Long facilityId; + private String name; + private String description; + private Vo vo; + + public Resource() { } + + public Resource(Long id, Long facilityId, Long voId, String name, String description) { + super(id); + this.setVoId(voId); + this.setFacilityId(facilityId); + this.setName(name); + this.setDescription(description); + } + + /** + * Should be used when RichResource is obtained from Perun + */ + public Resource(Long id, Long facilityId, Long voId, String name, String description, Vo vo) { + this(id, facilityId, voId, name, description); + this.setVo(vo); + } + + public Long getFacilityId() { + return facilityId; + } + + public void setFacilityId(Long facilityId) { + if (facilityId == null) { + throw new IllegalArgumentException("facilityId can't be null"); + } + + this.facilityId = facilityId; + } + + public Long getVoId() { + return voId; + } + + public void setVoId(Long voId) { + if (voId == null) { + throw new IllegalArgumentException("voId can't be null"); + } + + this.voId = voId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + if (Strings.isNullOrEmpty(name)) { + throw new IllegalArgumentException("name can't be null or empty"); + } + + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + if (description == null) { + throw new IllegalArgumentException("description can't be null"); + } + + this.description = description; + } + + public Vo getVo() { + return vo; + } + + public void setVo(Vo vo) { + this.vo = vo; + } + + @Override + public String toString() { + return "Resource{" + + "id=" + getId() + + ", voId=" + voId + + ", name='" + name + '\'' + + ", description='" + description + '\'' + + ", vo=" + vo + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + Resource resource = (Resource) o; + return Objects.equals(voId, resource.voId) && + Objects.equals(name, resource.name) && + Objects.equals(description, resource.description) && + Objects.equals(vo, resource.vo); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), voId, name, description, vo); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/UserExtSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/UserExtSource.java new file mode 100644 index 000000000..40448f8ba --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/UserExtSource.java @@ -0,0 +1,113 @@ +package cz.muni.ics.oidc.models; + +import com.google.common.base.Strings; +import java.sql.Timestamp; +import java.util.Objects; + +/** + * Model of Perun UserExtSource + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class UserExtSource extends Model { + + private ExtSource extSource; + private String login; + private int loa = 0; + private boolean persistent; + private Timestamp lastAccess; + + public UserExtSource() { + } + + public UserExtSource(Long id, ExtSource extSource, String login, int loa, boolean persistent, Timestamp lastAccess) { + super(id); + this.setExtSource(extSource); + this.setLogin(login); + this.setLoa(loa); + this.setPersistent(persistent); + this.setLastAccess(lastAccess); + } + + public ExtSource getExtSource() { + return extSource; + } + + public void setExtSource(ExtSource extSource) { + if (extSource == null) { + throw new IllegalArgumentException("extSource can't be null"); + } + + this.extSource = extSource; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + if (Strings.isNullOrEmpty(login)) { + throw new IllegalArgumentException("login can't be null or empty"); + } + + this.login = login; + } + + public int getLoa() { + return loa; + } + + public void setLoa(int loa) { + if (loa < 0) { + throw new IllegalArgumentException("loa has to be 0 or higher"); + } + + this.loa = loa; + } + + public boolean isPersistent() { + return persistent; + } + + public void setPersistent(boolean persistent) { + this.persistent = persistent; + } + + public Timestamp getLastAccess() { + return lastAccess; + } + + public void setLastAccess(Timestamp lastAccess) { + this.lastAccess = lastAccess; + } + + @Override + public String toString() { + return "UserExtSource{" + + "id=" + getId() + + ", extSource='" + extSource.toString() + '\'' + + ", login='" + login + '\'' + + ", loa=" + loa + + ", persistent=" + persistent + + ", lastAccess=" + lastAccess + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + UserExtSource that = (UserExtSource) o; + return loa == that.loa && + persistent == that.persistent && + Objects.equals(extSource, that.extSource) && + Objects.equals(login, that.login) && + Objects.equals(lastAccess, that.lastAccess); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), extSource, login, loa, persistent, lastAccess); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Vo.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Vo.java new file mode 100644 index 000000000..2e6f9ce52 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/Vo.java @@ -0,0 +1,71 @@ +package cz.muni.ics.oidc.models; + +import com.google.common.base.Strings; +import java.util.Objects; + +/** + * Virtual Organization (Vo) object model. + * + * @author Dominik Frantisek Bucik <bucik@.ics.muni.cz> + */ +public class Vo extends Model { + + private String name; + private String shortName; + + public Vo() { } + + public Vo(Long id, String name, String shortName) { + super(id); + this.setName(name); + this.setShortName(shortName); + } + + public String getName() { + return name; + } + + public void setName(String name) { + if (Strings.isNullOrEmpty(name)) { + throw new IllegalArgumentException("name can't be null or empty"); + } + + this.name = name; + } + + public String getShortName() { + return shortName; + } + + public void setShortName(String shortName) { + if (Strings.isNullOrEmpty(shortName)) { + throw new IllegalArgumentException("shortName can't be null or empty"); + } + + this.shortName = shortName; + } + + @Override + public String toString() { + return "Vo{" + + "id=" + this.getId() + + ", name='" + name + '\'' + + ", shortName='" + shortName + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + Vo vo = (Vo) o; + return Objects.equals(name, vo.name) && + Objects.equals(shortName, vo.shortName); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), name, shortName); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/enums/MemberStatus.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/enums/MemberStatus.java new file mode 100644 index 000000000..8c7a608b0 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/enums/MemberStatus.java @@ -0,0 +1,36 @@ +package cz.muni.ics.oidc.models.enums; + +/** + * Enum represents status of member in GROUP / VO. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public enum MemberStatus { + + VALID, + EXPIRED, + INVALID, + DISABLED, + SUSPENDED; + + public static MemberStatus fromString(String status) { + if (status == null) { + return null; + } + + switch(status.toUpperCase().trim()) { + case "VALID": + return VALID; + case "INVALID": + return INVALID; + case "EXPIRED": + return EXPIRED; + case "DISABLED": + return DISABLED; + case "SUSPENDED": + return SUSPENDED; + default: + return null; + } + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/enums/PerunAttrValueType.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/enums/PerunAttrValueType.java new file mode 100644 index 000000000..f2cd4da9d --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/enums/PerunAttrValueType.java @@ -0,0 +1,28 @@ +package cz.muni.ics.oidc.models.enums; + +public enum PerunAttrValueType { + + STRING, + INTEGER, + BOOLEAN, + ARRAY, + MAP_JSON, + MAP_KEY_VALUE; + + public static PerunAttrValueType parse(String str){ + if (str == null) { + return STRING; + } + + switch (str.toLowerCase()) { + case "integer": return INTEGER; + case "boolean": return BOOLEAN; + case "array": + case "list": return ARRAY; + case "map_json": return MAP_JSON; + case "map_key_value": return MAP_KEY_VALUE; + default: return STRING; + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/enums/PerunEntityType.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/enums/PerunEntityType.java new file mode 100644 index 000000000..f5fc86c6d --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/enums/PerunEntityType.java @@ -0,0 +1,11 @@ +package cz.muni.ics.oidc.models.enums; + +public enum PerunEntityType { + + USER, + GROUP, + VO, + FACILITY, + RESOURCE + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/exceptions/InconvertibleValueException.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/exceptions/InconvertibleValueException.java new file mode 100644 index 000000000..89f69b450 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/exceptions/InconvertibleValueException.java @@ -0,0 +1,29 @@ +package cz.muni.ics.oidc.models.exceptions; + +/** + * Exception represents state when value of an attribute cannot be converted into desired type. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class InconvertibleValueException extends RuntimeException { + + public InconvertibleValueException() { + super(); + } + + public InconvertibleValueException(String s) { + super(s); + } + + public InconvertibleValueException(String s, Throwable throwable) { + super(s, throwable); + } + + public InconvertibleValueException(Throwable throwable) { + super(throwable); + } + + protected InconvertibleValueException(String s, Throwable throwable, boolean b, boolean b1) { + super(s, throwable, b, b1); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/mappers/RpcMapper.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/mappers/RpcMapper.java new file mode 100644 index 000000000..9375a2fdf --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/models/mappers/RpcMapper.java @@ -0,0 +1,541 @@ +package cz.muni.ics.oidc.models.mappers; + +import com.fasterxml.jackson.databind.JsonNode; +import cz.muni.ics.oidc.exceptions.MissingFieldException; +import cz.muni.ics.oidc.models.AttributeMapping; +import cz.muni.ics.oidc.models.Aup; +import cz.muni.ics.oidc.models.ExtSource; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.Group; +import cz.muni.ics.oidc.models.Member; +import cz.muni.ics.oidc.models.PerunAttribute; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.models.Resource; +import cz.muni.ics.oidc.models.UserExtSource; +import cz.muni.ics.oidc.models.Vo; +import cz.muni.ics.oidc.models.enums.MemberStatus; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.springframework.util.StringUtils; + + +/** + * This class is mapping JsonNodes to object models. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class RpcMapper { + + public static final String ID = "id"; + public static final String UUID = "uuid"; + public static final String FIRST_NAME = "firstName"; + public static final String LAST_NAME = "lastName"; + public static final String PARENT_GROUP_ID = "parentGroupId"; + public static final String NAME = "name"; + public static final String DESCRIPTION = "description"; + public static final String VO_ID = "voId"; + public static final String USER_ID = "userId"; + public static final String STATUS = "status"; + public static final String FACILITY_ID = "facilityId"; + public static final String TYPE = "type"; + public static final String SHORT_NAME = "shortName"; + public static final String LOGIN = "login"; + public static final String EXT_SOURCE = "extSource"; + public static final String LOA = "loa"; + public static final String LAST_ACCESS = "lastAccess"; + public static final String PERSISTENT = "persistent"; + public static final String FRIENDLY_NAME = "friendlyName"; + public static final String NAMESPACE = "namespace"; + public static final String DISPLAY_NAME = "displayName"; + public static final String WRITABLE = "writable"; + public static final String UNIQUE = "unique"; + public static final String ENTITY = "entity"; + public static final String BASE_FRIENDLY_NAME = "baseFriendlyName"; + public static final String FRIENDLY_NAME_PARAMETER = "friendlyNameParameter"; + public static final String VALUE = "value"; + public static final String VALUE_CREATED_AT = "valueCreatedAt"; + public static final String VALUE_MODIFIED_AT = "valueModifiedAt"; + public static final String VERSION = "version"; + public static final String DATE = "date"; + public static final String LINK = "link"; + public static final String TEXT = "text"; + + /** + * Maps JsonNode to User model. + * + * @param json User in JSON format from Perun to be mapped. + * @return Mapped User object. + */ + public static PerunUser mapPerunUser(JsonNode json) { + if (json == null || json.isNull()) { + return null; + } + + Long id = getRequiredFieldAsLong(json, ID); + String firstName = getFieldAsString(json, FIRST_NAME); + String lastName = getRequiredFieldAsString(json, LAST_NAME); + + return new PerunUser(id, firstName, lastName); + } + + /** + * Maps JsonNode to List of USERS. + * + * @param jsonArray JSON array of users in JSON format from Perun to be mapped. + * @return List of users. + */ + public static List<PerunUser> mapPerunUsers(JsonNode jsonArray) { + if (jsonArray.isNull()) { + return new ArrayList<>(); + } + + return IntStream.range(0, jsonArray.size()). + mapToObj(jsonArray::get). + map(RpcMapper::mapPerunUser). + collect(Collectors.toList()); + } + + /** + * Maps JsonNode to Group model. + * + * @param json Group in JSON format from Perun to be mapped. + * @return Mapped Group object. + */ + public static Group mapGroup(JsonNode json) { + if (json == null || json.isNull()) { + return null; + } + + Long id = getRequiredFieldAsLong(json, ID); + Long parentGroupId = getFieldAsLong(json, PARENT_GROUP_ID); + String name = getRequiredFieldAsString(json, NAME); + String description = getFieldAsString(json, DESCRIPTION); + Long voId = getRequiredFieldAsLong(json, VO_ID); + String uuid = getRequiredFieldAsString(json, UUID); + + return new Group(id, parentGroupId, name, description, null, uuid, voId); + } + + /** + * Maps JsonNode to List of Groups. + * + * @param jsonArray JSON array of groups in JSON format from Perun to be mapped. + * @return List of groups. + */ + public static List<Group> mapGroups(JsonNode jsonArray) { + if (jsonArray.isNull()) { + return new ArrayList<>(); + } + + List<Group> result = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + JsonNode groupNode = jsonArray.get(i); + Group mappedGroup = RpcMapper.mapGroup(groupNode); + result.add(mappedGroup); + } + + return result; + } + + /** + * Maps JsonNode to Facility model. + * + * @param json Facility in JSON format from Perun to be mapped. + * @return Mapped Facility object. + */ + public static Facility mapFacility(JsonNode json) { + if (json == null || json.isNull()) { + return null; + } + + Long id = getRequiredFieldAsLong(json, ID); + String name = getRequiredFieldAsString(json, NAME); + String description = getFieldAsString(json, DESCRIPTION); + + return new Facility(id, name, description); + } + + /** + * Maps JsonNode to List of Facilities. + * + * @param jsonArray JSON array of facilities in JSON format from Perun to be mapped. + * @return List of facilities. + */ + public static List<Facility> mapFacilities(JsonNode jsonArray) { + if (jsonArray.isNull()) { + return new ArrayList<>(); + } + + List<Facility> result = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + JsonNode facilityNode = jsonArray.get(i); + Facility mappedFacility = RpcMapper.mapFacility(facilityNode); + result.add(mappedFacility); + } + + return result; + } + + /** + * Maps JsonNode to Member model. + * + * @param json Member in JSON format from Perun to be mapped. + * @return Mapped Member object. + */ + public static Member mapMember(JsonNode json) { + if (json == null || json.isNull()) { + return null; + } + + Long id = getRequiredFieldAsLong(json, ID); + Long userId = getRequiredFieldAsLong(json, USER_ID); + Long voId = getRequiredFieldAsLong(json, VO_ID); + MemberStatus status = MemberStatus.fromString(getRequiredFieldAsString(json, STATUS)); + + return new Member(id, userId, voId, status); + } + + /** + * Maps JsonNode to List of Members. + * + * @param jsonArray JSON array of members in JSON format from Perun to be mapped. + * @return List of members. + */ + public static List<Member> mapMembers(JsonNode jsonArray) { + if (jsonArray.isNull()) { + return new ArrayList<>(); + } + + List<Member> members = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + JsonNode memberNode = jsonArray.get(i); + Member mappedMember = RpcMapper.mapMember(memberNode); + members.add(mappedMember); + } + + return members; + } + + /** + * Maps JsonNode to Resource model. + * + * @param json Resource in JSON format from Perun to be mapped. + * @return Mapped Resource object. + */ + public static Resource mapResource(JsonNode json) { + if (json == null || json.isNull()) { + return null; + } + + Long id = getRequiredFieldAsLong(json, ID); + Long voId = getRequiredFieldAsLong(json, VO_ID); + Long facilityId = getRequiredFieldAsLong(json, FACILITY_ID); + String name = getRequiredFieldAsString(json, NAME); + String description = getFieldAsString(json, DESCRIPTION); + + Vo vo = null; + if (json.hasNonNull("vo")) { + JsonNode voJson = json.get("vo"); + vo = RpcMapper.mapVo(voJson); + } + + return new Resource(id, voId, facilityId, name, description, vo); + } + + /** + * Maps JsonNode to List of Resources. + * + * @param jsonArray JSON array of resources in JSON format from Perun to be mapped. + * @return List of resources. + */ + public static List<Resource> mapResources(JsonNode jsonArray) { + if (jsonArray.isNull()) { + return new ArrayList<>(); + } + + List<Resource> resources = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + JsonNode resource = jsonArray.get(i); + Resource mappedResource = RpcMapper.mapResource(resource); + resources.add(mappedResource); + } + + return resources; + } + + /** + * Maps JsonNode to ExtSource model. + * + * @param json ExtSource in JSON format from Perun to be mapped. + * @return Mapped ExtSource object. + */ + public static ExtSource mapExtSource(JsonNode json) { + if (json == null || json.isNull()) { + return null; + } + + Long id = getRequiredFieldAsLong(json, ID); + String name = getRequiredFieldAsString(json, NAME); + String type = getRequiredFieldAsString(json, TYPE); + + return new ExtSource(id, name, type); + } + + /** + * Maps JsonNode to List of ExtSources. + * + * @param jsonArray JSON array of extSources in JSON format from Perun to be mapped. + * @return List of extSources. + */ + public static List<ExtSource> mapExtSources(JsonNode jsonArray) { + if (jsonArray.isNull()) { + return new ArrayList<>(); + } + + List<ExtSource> extSources = new ArrayList<>(); + + for (int i = 0; i < jsonArray.size(); i++) { + JsonNode extSource = jsonArray.get(i); + ExtSource mappedExtSource = RpcMapper.mapExtSource(extSource); + extSources.add(mappedExtSource); + } + + return extSources; + } + + /** + * Maps JsonNode to VO model. + * + * @param json VO in JSON format from Perun to be mapped. + * @return Mapped VO object. + */ + public static Vo mapVo(JsonNode json) { + if (json == null || json.isNull()) { + return null; + } + + Long id = getRequiredFieldAsLong(json, ID); + String name = getRequiredFieldAsString(json, NAME); + String shortName = getRequiredFieldAsString(json, SHORT_NAME); + + return new Vo(id, name, shortName); + } + + /** + * Maps JsonNode to List of VOs. + * + * @param jsonArray JSON array of VOs in JSON format from Perun to be mapped. + * @return List of VOs. + */ + public static List<Vo> mapVos(JsonNode jsonArray) { + if (jsonArray.isNull()) { + return new ArrayList<>(); + } + + List<Vo> vos = new ArrayList<>(); + + for (int i = 0; i < jsonArray.size(); i++) { + JsonNode voJson = jsonArray.get(i); + Vo mappedVo = RpcMapper.mapVo(voJson); + vos.add(mappedVo); + } + + return vos; + } + + /** + * Maps JsonNode to UserExtSource model. + * + * @param json UserExtSource in JSON format from Perun to be mapped. + * @return Mapped UserExtSource object. + */ + public static UserExtSource mapUserExtSource(JsonNode json) { + if (json == null || json.isNull()) { + return null; + } + + Long id = getRequiredFieldAsLong(json, ID); + String login = getRequiredFieldAsString(json, LOGIN); + ExtSource extSource = RpcMapper.mapExtSource(getRequiredFieldAsJsonNode(json, EXT_SOURCE)); + int loa = getRequiredFieldAsInt(json, LOA); + boolean persistent = getRequiredFieldAsBoolean(json, PERSISTENT); + Timestamp lastAccess = Timestamp.valueOf(getRequiredFieldAsString(json, LAST_ACCESS)); + + return new UserExtSource(id, extSource, login, loa, persistent, lastAccess); + } + + /** + * Maps JsonNode to List of UserExtSources. + * + * @param jsonArray JSON array of userExtSources in JSON format from Perun to be mapped. + * @return List of userExtSources. + */ + public static List<UserExtSource> mapUserExtSources(JsonNode jsonArray) { + if (jsonArray.isNull()) { + return new ArrayList<>(); + } + + List<UserExtSource> userExtSources = new ArrayList<>(); + + for (int i = 0; i < jsonArray.size(); i++) { + JsonNode userExtSource = jsonArray.get(i); + UserExtSource mappedUes = RpcMapper.mapUserExtSource(userExtSource); + userExtSources.add(mappedUes); + } + + return userExtSources; + } + + /** + * Maps JsonNode to PerunAttribute model. + * + * @param json PerunAttribute in JSON format from Perun to be mapped. + * @return Mapped PerunAttribute object. + */ + public static PerunAttribute mapAttribute(JsonNode json) { + if (json == null || json.isNull()) { + return null; + } + + Long id = getRequiredFieldAsLong(json, ID); + String friendlyName = getRequiredFieldAsString(json, FRIENDLY_NAME); + String namespace = getRequiredFieldAsString(json, NAMESPACE); + String description = getFieldAsString(json, DESCRIPTION); + String type = getRequiredFieldAsString(json, TYPE); + String displayName = getRequiredFieldAsString(json, DISPLAY_NAME); + boolean writable = getRequiredFieldAsBoolean(json, WRITABLE); + boolean unique = getRequiredFieldAsBoolean(json, UNIQUE); + String entity = getRequiredFieldAsString(json, ENTITY); + String baseFriendlyName = getFieldAsString(json, BASE_FRIENDLY_NAME); + String friendlyNameParameter = getFieldAsString(json, FRIENDLY_NAME_PARAMETER); + JsonNode value = getFieldAsJsonNode(json, VALUE); + String valueCreatedAt = getFieldAsString(json, VALUE_CREATED_AT); + if (!StringUtils.hasText(valueCreatedAt)) { + valueCreatedAt = null; + } + String valueModifiedAt = getFieldAsString(json, VALUE_MODIFIED_AT); + if (!StringUtils.hasText(valueModifiedAt)) { + valueModifiedAt = null; + } + + return new PerunAttribute(id, friendlyName, namespace, description, type, displayName, + writable, unique, entity, baseFriendlyName, friendlyNameParameter, value, valueCreatedAt, valueModifiedAt); + } + + /** + * Map JsonNode to Map of Perun attributes + * @param jsonNode attributes as array in JSON format to be mapped + * @return Map of PerunAttributes mapped from JsonNode, where key = URN, value = Attribute + */ + public static Map<String, PerunAttribute> mapAttributes(JsonNode jsonNode, Set<AttributeMapping> attrMappings) { + Map<String, PerunAttribute> res = new HashMap<>(); + Map<String, PerunAttribute> attributesAsMap = new HashMap<>(); + + for (int i = 0; i < jsonNode.size(); i++) { + JsonNode attribute = jsonNode.get(i); + PerunAttribute mappedAttribute = mapAttribute(attribute); + attributesAsMap.put(mappedAttribute.getUrn(), mappedAttribute); + } + + for (AttributeMapping mapping: attrMappings) { + String attrKey = mapping.getRpcName(); + if (attributesAsMap.containsKey(attrKey)) { + PerunAttribute attribute = attributesAsMap.get(attrKey); + res.put(mapping.getIdentifier(), attribute); + } else { + res.put(mapping.getIdentifier(), null); + } + } + + return res; + } + + /** + * Map JsonNode to list of Aup + * @param json Aup in JSON format + * @return Mapped Aup + */ + public static Aup mapAup(JsonNode json) { + Aup aup = new Aup(); + aup.setVersion(getFieldAsString(json, VERSION)); + aup.setDate(getFieldAsString(json, DATE)); + aup.setLink(getFieldAsString(json, LINK)); + aup.setText(getFieldAsString(json, TEXT)); + aup.setSignedOn(json.hasNonNull(Aup.SIGNED_ON) ? json.get(Aup.SIGNED_ON).asText() : null); + return aup; + } + + private static Long getRequiredFieldAsLong(JsonNode json, String name) { + if (!json.hasNonNull(name)) { + throw new MissingFieldException(); + } + return json.get(name).asLong(); + } + + private static Long getFieldAsLong(JsonNode json, String name) { + if (!json.hasNonNull(name)) { + return 0L; + } + return json.get(name).asLong(); + } + + private static int getRequiredFieldAsInt(JsonNode json, String name) { + if (!json.hasNonNull(name)) { + throw new MissingFieldException(); + } + return json.get(name).asInt(); + } + + private static int getFieldAsInt(JsonNode json, String name) { + if (!json.hasNonNull(name)) { + return 0; + } + return json.get(name).asInt(); + } + + private static boolean getRequiredFieldAsBoolean(JsonNode json, String name) { + if (!json.hasNonNull(name)) { + throw new MissingFieldException(); + } + return json.get(name).asBoolean(); + } + + private static boolean getFieldAsBoolean(JsonNode json, String name) { + if (!json.hasNonNull(name)) { + return false; + } + return json.get(name).asBoolean(); + } + + private static String getRequiredFieldAsString(JsonNode json, String name) { + if (!json.hasNonNull(name)) { + throw new MissingFieldException(); + } + return json.get(name).asText(); + } + + private static String getFieldAsString(JsonNode json, String name) { + if (!json.hasNonNull(name)) { + return ""; + } + return json.get(name).asText(); + } + + private static JsonNode getRequiredFieldAsJsonNode(JsonNode json, String name) { + if (!json.hasNonNull(name)) { + throw new MissingFieldException(); + } + return json.get(name); + } + + private static JsonNode getFieldAsJsonNode(JsonNode json, String name) { + return json.get(name); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/IdpMetadataBeans.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/IdpMetadataBeans.java new file mode 100644 index 000000000..e3f281469 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/IdpMetadataBeans.java @@ -0,0 +1,44 @@ +package cz.muni.ics.oidc.saml; + +import java.io.File; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.params.HttpClientParams; +import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; +import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; +import org.opensaml.saml2.metadata.provider.MetadataProvider; +import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.opensaml.xml.parse.ParserPool; +import org.springframework.context.annotation.Bean; +import org.springframework.security.saml.metadata.ExtendedMetadata; +import org.springframework.security.saml.metadata.ExtendedMetadataDelegate; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +@Component +public class IdpMetadataBeans { + + @Bean(name = "idpMetadata") + public ExtendedMetadataDelegate idpMetadata(SamlProperties samlProperties, + ExtendedMetadata extendedMetadata, + ParserPool parserPool) throws MetadataProviderException + { + MetadataProvider mp; + if (StringUtils.hasText(samlProperties.getIdpMetadataUrl())) { + HttpClientParams clientParams = new HttpClientParams(); + clientParams.setSoTimeout(60000); + HttpClient httpClient = new HttpClient(clientParams); + + HTTPMetadataProvider httpMp = new HTTPMetadataProvider(null, httpClient, + samlProperties.getIdpMetadataUrl()); + httpMp.setParserPool(parserPool); + mp = httpMp; + } else { + FilesystemMetadataProvider fsmp = new FilesystemMetadataProvider( + new File(samlProperties.getIdpMetadataFile())); + fsmp.setParserPool(parserPool); + mp = fsmp; + } + return new ExtendedMetadataDelegate(mp, extendedMetadata); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunOidcLogoutSuccessHandler.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunOidcLogoutSuccessHandler.java new file mode 100644 index 000000000..2598aa988 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunOidcLogoutSuccessHandler.java @@ -0,0 +1,52 @@ +package cz.muni.ics.oidc.saml; + +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_POST_LOGOUT_REDIRECT_URI; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_STATE; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; +import org.springframework.web.util.UriComponentsBuilder; + +public class PerunOidcLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler { + + private static final Logger log = LoggerFactory.getLogger(PerunOidcLogoutSuccessHandler.class); + + @Override + protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) { + String targetUrl = super.determineTargetUrl(request, response); + if (getDefaultTargetUrl().equals(targetUrl)) { + String referer = request.getHeader("Referer"); + if (StringUtils.hasText(referer)) { + try { + MultiValueMap<String, String> params = UriComponentsBuilder.fromHttpUrl(referer) + .build().getQueryParams(); + UriComponentsBuilder builder; + if (params != null && params.containsKey(PARAM_POST_LOGOUT_REDIRECT_URI)) { + String postLogoutRedirectUri = params.getFirst(PARAM_POST_LOGOUT_REDIRECT_URI); + log.trace("Reconstruct from post_logout_redirect_uri: {}", postLogoutRedirectUri); + postLogoutRedirectUri = URLDecoder.decode(postLogoutRedirectUri, StandardCharsets.UTF_8.toString()); + builder = UriComponentsBuilder.fromUriString(postLogoutRedirectUri); + if (params.containsKey(PARAM_STATE) && StringUtils.hasText(params.getFirst(PARAM_STATE))) { + String state = params.getFirst(PARAM_STATE); + log.trace("Add state param to target: {}", state); + builder.queryParam(PARAM_STATE, state); + } + targetUrl = builder.build().toString(); + } + } catch (IllegalArgumentException | UnsupportedEncodingException e) { + log.debug("Invalid URL or error has occurred when parsing it, do not use it and fall back"); + } + } + } + return targetUrl; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlAuthenticationProvider.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlAuthenticationProvider.java new file mode 100644 index 000000000..4f043ed0d --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlAuthenticationProvider.java @@ -0,0 +1,51 @@ +package cz.muni.ics.oidc.saml; + +import cz.muni.ics.oidc.models.PerunUser; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.saml.SAMLAuthenticationProvider; +import org.springframework.security.saml.SAMLCredential; + +public class PerunSamlAuthenticationProvider extends SAMLAuthenticationProvider { + + private static final Logger log = LoggerFactory.getLogger(PerunSamlAuthenticationProvider.class); + + private static final GrantedAuthority ROLE_USER = new SimpleGrantedAuthority("ROLE_USER"); + private static final GrantedAuthority ROLE_ADMIN = new SimpleGrantedAuthority("ROLE_ADMIN"); + + private final List<Long> adminIds = new ArrayList<>(); + + public PerunSamlAuthenticationProvider(List<String> adminIds) { + for (String id : adminIds) { + long l = Long.parseLong(id); + this.adminIds.add(l); + log.debug("added user {} as admin", l); + } + } + + @Override + protected Object getPrincipal(SAMLCredential credential, Object userDetail) { + PerunUser user = (PerunUser) userDetail; + return new User(String.valueOf(user.getId()), credential.getRemoteEntityID(), + getEntitlements(credential, userDetail)); + } + + @Override + public Collection<? extends GrantedAuthority> getEntitlements(SAMLCredential credential, Object userDetail) { + PerunUser user = (PerunUser) userDetail; + Collection<GrantedAuthority> authorities = new ArrayList<>(); + authorities.add(ROLE_USER); + if (adminIds.contains(user.getId())) { + authorities.add(ROLE_ADMIN); + log.debug("adding admin role for user with Perun ID: {}", user.getId()); + } + return authorities; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlAuthenticationSuccessHandler.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlAuthenticationSuccessHandler.java new file mode 100644 index 000000000..47fc6105d --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlAuthenticationSuccessHandler.java @@ -0,0 +1,57 @@ +package cz.muni.ics.oidc.saml; + +import static cz.muni.ics.openid.connect.web.AuthenticationTimeStamper.AUTH_TIMESTAMP; + +import cz.muni.ics.oidc.server.PerunOIDCTokenService; +import java.io.IOException; +import java.util.Date; +import java.util.stream.Collectors; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.opensaml.saml2.core.AuthnContext; +import org.opensaml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml2.core.AuthnStatement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.providers.ExpiringUsernameAuthenticationToken; +import org.springframework.security.saml.SAMLCredential; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.security.web.authentication.WebAuthenticationDetails; + +public class PerunSamlAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { + + private final static Logger log = LoggerFactory.getLogger(PerunSamlAuthenticationSuccessHandler.class); + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, + HttpServletResponse response, + Authentication authentication) + throws ServletException, IOException + { + Date authTimestamp = new Date(); + request.getSession().setAttribute(AUTH_TIMESTAMP, authTimestamp); + if (authentication instanceof ExpiringUsernameAuthenticationToken) { + ExpiringUsernameAuthenticationToken token = (ExpiringUsernameAuthenticationToken) authentication; + Object details = token.getDetails(); + if (details instanceof WebAuthenticationDetails) { + WebAuthenticationDetails webDetails = (WebAuthenticationDetails) details; + log.info("successful authentication, remote IP address {}", webDetails.getRemoteAddress()); + } + setAcrToSession(request, token); + } + super.onAuthenticationSuccess(request, response, authentication); + } + + private void setAcrToSession(HttpServletRequest request, Authentication token) { + String acrs = ((SAMLCredential) token.getCredentials()).getAuthenticationAssertion() + .getAuthnStatements().stream() + .map(AuthnStatement::getAuthnContext) + .map(AuthnContext::getAuthnContextClassRef) + .map(AuthnContextClassRef::getAuthnContextClassRef) + .collect(Collectors.joining()); + request.getSession(true).setAttribute(PerunOIDCTokenService.SESSION_PARAM_ACR, acrs);; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlEntryPoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlEntryPoint.java new file mode 100644 index 000000000..4f3b301a6 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlEntryPoint.java @@ -0,0 +1,248 @@ +package cz.muni.ics.oidc.saml; + +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.EFILTER_PREFIX; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.FILTER_PREFIX; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.IDP_ENTITY_ID_PREFIX; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_PROMPT; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.REFEDS_MFA; + +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig; +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.server.filters.PerunFilterConstants; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.opensaml.common.SAMLException; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.saml.SAMLConstants; +import org.springframework.security.saml.SAMLEntryPoint; +import org.springframework.security.saml.context.SAMLMessageContext; +import org.springframework.security.saml.util.SAMLUtil; +import org.springframework.security.saml.websso.WebSSOProfileOptions; +import org.springframework.util.StringUtils; + +public class PerunSamlEntryPoint extends SAMLEntryPoint { + + private static final Logger log = LoggerFactory.getLogger(PerunSamlEntryPoint.class); + + private final PerunAdapter perunAdapter; + private final PerunOidcConfig config; + private final FacilityAttrsConfig facilityAttrsConfig; + + @Autowired + public PerunSamlEntryPoint(PerunAdapter perunAdapter, PerunOidcConfig config, + FacilityAttrsConfig facilityAttrsConfig) + { + this.perunAdapter = perunAdapter; + this.config = config; + this.facilityAttrsConfig = facilityAttrsConfig; + } + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) + throws IOException, ServletException { + try { + SAMLMessageContext context = contextProvider.getLocalAndPeerEntity(request, response); + + if (isECP(context)) { + initializeECP(request, context, e); + } else if (isDiscovery(context)) { + initializeDiscovery(context); + } else { + initializeSSO(request, context, e); + } + } catch (SAMLException | MetadataProviderException | MessageEncodingException e1) { + log.debug("Error initializing entry point", e1); + throw new ServletException(e1); + } + } + + protected WebSSOProfileOptions getExtendedOptions(HttpServletRequest request, + SAMLMessageContext context, + AuthenticationException exception) + throws MetadataProviderException + { + WebSSOProfileOptions options = super.getProfileOptions(context, exception); + addExtraParams(request, options); + return options; + } + + + // copy from super class to call our getProfileOptions + protected void initializeECP(HttpServletRequest request, SAMLMessageContext context, + AuthenticationException e) + throws MetadataProviderException, SAMLException, MessageEncodingException + { + WebSSOProfileOptions options = getExtendedOptions(request, context, e); + log.debug("Processing SSO using ECP profile"); + webSSOprofileECP.sendAuthenticationRequest(context, options); + samlLogger.log(SAMLConstants.AUTH_N_REQUEST, SAMLConstants.SUCCESS, context); + } + + // copy from super class to call our getProfileOptions + protected void initializeSSO(HttpServletRequest request, SAMLMessageContext context, + AuthenticationException e) + throws MetadataProviderException, SAMLException, MessageEncodingException + { + WebSSOProfileOptions options = getExtendedOptions(request, context, e); + AssertionConsumerService consumerService = SAMLUtil.getConsumerService( + (SPSSODescriptor) context.getLocalEntityRoleMetadata(), options.getAssertionConsumerIndex()); + + // HoK WebSSO + if (SAMLConstants.SAML2_HOK_WEBSSO_PROFILE_URI.equals(consumerService.getBinding())) { + if (webSSOprofileHoK == null) { + log.warn("WebSSO HoK profile was specified to be used, but profile is not " + + "configured in the EntryPoint, HoK will be skipped"); + } else { + log.debug("Processing SSO using WebSSO HolderOfKey profile"); + webSSOprofileHoK.sendAuthenticationRequest(context, options); + samlLogger.log(SAMLConstants.AUTH_N_REQUEST, SAMLConstants.SUCCESS, context); + return; + } + } + + // Ordinary WebSSO + log.debug("Processing SSO using WebSSO profile"); + webSSOprofile.sendAuthenticationRequest(context, options); + samlLogger.log(SAMLConstants.AUTH_N_REQUEST, SAMLConstants.SUCCESS, context); + } + + private void addExtraParams(HttpServletRequest request, WebSSOProfileOptions options) { + log.debug("Transforming OIDC params to SAML"); + processAcrValues(request, options); + processForceAuthn(request, options); + processPrompt(request, options); + } + + private void processForceAuthn(HttpServletRequest request, WebSSOProfileOptions options) { + if (PerunSamlUtils.needsReAuthByForceAuthn(request)) { + log.debug("Transformed forceAuthn parameter to SAML forceAuthn=true"); + options.setForceAuthN(true); + } + } + + private void processPrompt(HttpServletRequest request, WebSSOProfileOptions options) { + if (PerunSamlUtils.needsReAuthByPrompt(request)) { + log.debug("Transformed prompt parameter ({}) to SAML forceAuthn=true", + request.getParameter(PARAM_PROMPT)); + options.setForceAuthN(true); + } + } + + private void processAcrValues(HttpServletRequest request, WebSSOProfileOptions options) { + String acrValues = request.getParameter(PerunFilterConstants.PARAM_ACR_VALUES); + log.debug("Processing acr_values parameter: {}", acrValues); + List<String> acrs = convertAcrValuesToList(acrValues); + + if (!hasAcrForcingIdp(acrs)) { + String clientId = request.getParameter(PerunFilterConstants.PARAM_CLIENT_ID); + String idpFilter = extractIdpFilterForRp(clientId); + if (idpFilter != null) { + log.debug("Added IdP filter as SAML AuthnContextClassRef ({})", idpFilter); + acrs.add(idpFilter); + } + } + + if (PerunSamlUtils.needsReAuthByMfa(request)) { + log.debug("ACRs include {}, added forceAuthn to proxy request", REFEDS_MFA); + options.setForceAuthN(true); + } + + if (acrs.size() > 0) { + options.setAuthnContexts(acrs); + log.debug("Transformed acr_values ({}) to SAML AuthnContextClassRef ({})", + acrValues, options.getAuthnContexts()); + } + } + + private List<String> convertAcrValuesToList(String acrValues) { + List<String> acrs = new ArrayList<>(); + if (StringUtils.hasText(acrValues)) { + String[] parts = acrValues.split(" "); + if (parts.length > 0) { + for (String acr: parts) { + if (StringUtils.hasText(acr)) { + acrs.add(acr); + } + } + } + } + return acrs; + } + + private boolean hasAcrForcingIdp(List<String> acrs) { + boolean hasIdpEntityId = acrs != null + && !acrs.isEmpty() + && acrs.stream().anyMatch( + acr -> StringUtils.hasText(acr) && acr.startsWith(IDP_ENTITY_ID_PREFIX) + ); + + if (hasIdpEntityId) { + log.debug("Request contains ACR to force specific IdP, no configured IdP filter will be used"); + } + return hasIdpEntityId; + } + + private String extractIdpFilterForRp(String clientId) { + if (!config.isAskPerunForIdpFiltersEnabled()) { + return null; + } + Facility facility = null; + if (clientId != null) { + facility = perunAdapter.getFacilityByClientId(clientId); + } + Map<String, PerunAttributeValue> filterAttributes = new HashMap<>(); + if (facility != null) { + filterAttributes = this.getFacilityFilterAttributes(facility); + } + + String idpFilterAcr = null; + String idpFilter = fetchRpIdpFilter(filterAttributes, facilityAttrsConfig.getWayfFilterAttr()); + if (StringUtils.hasText(idpFilter)) { + idpFilterAcr = FILTER_PREFIX + idpFilter; + } else { + String idpEFilter = fetchRpIdpFilter(filterAttributes, facilityAttrsConfig.getWayfEFilterAttr()); + if (StringUtils.hasText(idpEFilter)) { + idpFilterAcr = EFILTER_PREFIX + idpEFilter; + } + } + return idpFilterAcr; + } + + private Map<String, PerunAttributeValue> getFacilityFilterAttributes(Facility facility) { + if (facility != null && facility.getId() != null) { + List<String> attrsToFetch = new ArrayList<>(); + attrsToFetch.add(facilityAttrsConfig.getWayfEFilterAttr()); + attrsToFetch.add(facilityAttrsConfig.getWayfFilterAttr()); + return perunAdapter.getFacilityAttributeValues(facility, attrsToFetch); + } + return new HashMap<>(); + } + + private String fetchRpIdpFilter(Map<String, PerunAttributeValue> filterAttributes, String attrName) { + String result = null; + if (filterAttributes.get(attrName) != null) { + PerunAttributeValue filterAttribute = filterAttributes.get(attrName); + if (filterAttribute != null && filterAttribute.valueAsString() != null) { + result = filterAttribute.valueAsString(); + } + } + return result; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlProcessingFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlProcessingFilter.java new file mode 100644 index 000000000..17b68dd52 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlProcessingFilter.java @@ -0,0 +1,50 @@ +package cz.muni.ics.oidc.saml; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.saml.SAMLProcessingFilter; + +public class PerunSamlProcessingFilter extends SAMLProcessingFilter { + + private static final Logger log = LoggerFactory.getLogger(PerunSamlProcessingFilter.class); + + @Override + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) + throws IOException, ServletException { + log.debug("doFilter"); + super.doFilter(req, res, chain); + } + + @Override + protected void successfulAuthentication(HttpServletRequest request, + HttpServletResponse response, FilterChain chain, + Authentication authResult) + throws IOException, ServletException { + log.debug("successful authentication"); + super.successfulAuthentication(request, response, chain, authResult); + } + + @Override + protected void unsuccessfulAuthentication(HttpServletRequest request, + HttpServletResponse response, + AuthenticationException failed) + throws IOException, ServletException { + log.debug("unsuccessfull authentication"); + super.unsuccessfulAuthentication(request, response, failed); + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { + log.debug("Attempting authentication"); + return super.attemptAuthentication(request, response); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlUserDetailsService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlUserDetailsService.java new file mode 100644 index 000000000..612b23f2c --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlUserDetailsService.java @@ -0,0 +1,32 @@ +package cz.muni.ics.oidc.saml; + +import cz.muni.ics.oidc.server.PerunPrincipal; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.filters.FiltersUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.saml.SAMLCredential; +import org.springframework.security.saml.userdetails.SAMLUserDetailsService; + +public class PerunSamlUserDetailsService implements SAMLUserDetailsService { + + private static final Logger log = LoggerFactory.getLogger(PerunSamlUserDetailsService.class); + + private final PerunAdapter perunAdapter; + + @Autowired + public PerunSamlUserDetailsService(PerunAdapter perunAdapter) { + this.perunAdapter = perunAdapter; + } + + @Override + public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException { + log.debug("Loading user for SAML credential"); + PerunPrincipal p = FiltersUtils.getPerunPrincipal(credential); + log.debug("Fetching user from perun ({})", p); + return perunAdapter.getPreauthenticatedUserId(p); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlUtils.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlUtils.java new file mode 100644 index 000000000..a9bde3438 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlUtils.java @@ -0,0 +1,42 @@ +package cz.muni.ics.oidc.saml; + +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_ACR_VALUES; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_FORCE_AUTHN; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_PROMPT; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PROMPT_LOGIN; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PROMPT_SELECT_ACCOUNT; + +import cz.muni.ics.oidc.server.filters.PerunFilterConstants; +import javax.servlet.ServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +public class PerunSamlUtils { + + private static final Logger log = LoggerFactory.getLogger(PerunSamlUtils.class); + + public static boolean needsReAuthByPrompt(ServletRequest request) { + String prompt = request.getParameter(PARAM_PROMPT); + boolean res = (StringUtils.hasText(prompt) && (PROMPT_LOGIN.equalsIgnoreCase(prompt) + || PROMPT_SELECT_ACCOUNT.equalsIgnoreCase(prompt))); + log.debug("requires reAuth by prompt - {}", res); + return res; + } + + public static boolean needsReAuthByForceAuthn(ServletRequest request) { + String forceAuthn = request.getParameter(PARAM_FORCE_AUTHN); + boolean res = (StringUtils.hasText(forceAuthn) && Boolean.parseBoolean(forceAuthn)); + log.debug("requires reAuth by forceAuthn - {}", res); + return res; + } + + public static boolean needsReAuthByMfa(ServletRequest request) { + String acrValues = request.getParameter(PARAM_ACR_VALUES); + boolean res = StringUtils.hasText(acrValues) + && acrValues.contains(PerunFilterConstants.REFEDS_MFA); + log.debug("requires reAuth by MFA acr - {}", res); + return res; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunWebSSOProfileConsumerImpl.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunWebSSOProfileConsumerImpl.java new file mode 100644 index 000000000..1f7f15424 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunWebSSOProfileConsumerImpl.java @@ -0,0 +1,86 @@ +package cz.muni.ics.oidc.saml; + +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import org.opensaml.saml2.core.AuthnContext; +import org.opensaml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml2.core.AuthnStatement; +import org.opensaml.saml2.core.RequestedAuthnContext; +import org.springframework.security.authentication.CredentialsExpiredException; +import org.springframework.security.authentication.InsufficientAuthenticationException; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.saml.context.SAMLMessageContext; +import org.springframework.security.saml.websso.WebSSOProfileConsumerImpl; + +public class PerunWebSSOProfileConsumerImpl extends WebSSOProfileConsumerImpl { + + private boolean enableComparison = false; + private Set<String> reservedPrefixes; + + public void setEnableComparison(boolean enableComparison) { + this.enableComparison = enableComparison; + } + + public void setReservedPrefixes(Set<String> reservedPrefixes) { + this.reservedPrefixes = reservedPrefixes; + } + + @Override + protected void verifyAuthenticationStatement(AuthnStatement auth, + RequestedAuthnContext requestedAuthnContext, + SAMLMessageContext context) + throws AuthenticationException + { + // Validate users session is still valid + if (auth.getSessionNotOnOrAfter() != null && auth.getSessionNotOnOrAfter().isBeforeNow()) { + throw new CredentialsExpiredException("Authentication session is not valid on or after " + + auth.getSessionNotOnOrAfter()); + } + + // Verify context + verifyAuthnContext(requestedAuthnContext, auth.getAuthnContext(), context); + } + + @Override + protected void verifyAuthnContext(RequestedAuthnContext requestedAuthnContext, + AuthnContext receivedContext, SAMLMessageContext context) + throws InsufficientAuthenticationException + { + if (!enableComparison) { + return; + } + if (filterOutConditionsMet(requestedAuthnContext)) { + filterOutPrefixedAcrs(requestedAuthnContext); + } + super.verifyAuthnContext(requestedAuthnContext, receivedContext, context); + } + + private boolean filterOutConditionsMet(RequestedAuthnContext requestedAuthnContext) { + if (requestedAuthnContext == null) { + return false; + } else { + List<AuthnContextClassRef> requested = requestedAuthnContext.getAuthnContextClassRefs(); + return requested != null + && !requested.isEmpty() + && reservedPrefixes != null + && !reservedPrefixes.isEmpty(); + } + } + + private void filterOutPrefixedAcrs(RequestedAuthnContext requestedAuthnContext) { + List<AuthnContextClassRef> requested = requestedAuthnContext.getAuthnContextClassRefs(); + Iterator<AuthnContextClassRef> it = requested.iterator(); + while (it.hasNext()) { + AuthnContextClassRef accr = it.next(); + if (reservedPrefixes == null || reservedPrefixes.isEmpty()) { + continue; + } + for (String prefix : reservedPrefixes) { + if (accr.getAuthnContextClassRef().startsWith(prefix)) { + it.remove(); + } + } + } + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlInvalidateSessionFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlInvalidateSessionFilter.java new file mode 100644 index 000000000..bee72436d --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlInvalidateSessionFilter.java @@ -0,0 +1,81 @@ +package cz.muni.ics.oidc.saml; + +import static org.springframework.http.HttpHeaders.REFERER; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +public class SamlInvalidateSessionFilter extends GenericFilterBean { + + private static final Logger log = LoggerFactory.getLogger(SamlInvalidateSessionFilter.class); + private final AntPathRequestMatcher matcher; + + private final String idpEntityId; + private final String proxySpEntityId; + private final boolean proxyEnabled; + private final String oidcIssuer; + private final SecurityContextLogoutHandler contextLogoutHandler; + + public SamlInvalidateSessionFilter(String pattern, + String idpEntityId, + String oidcIssuer, + boolean proxyEnabled, + String proxySpEntityId, + SecurityContextLogoutHandler contextLogoutHandler) + { + this.matcher = new AntPathRequestMatcher(pattern); + this.idpEntityId = idpEntityId; + this.oidcIssuer = oidcIssuer; + this.proxyEnabled = proxyEnabled; + this.proxySpEntityId = proxySpEntityId; + this.contextLogoutHandler = contextLogoutHandler; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse res = (HttpServletResponse) response; + if (matcher.matches(req)) { + String referer = req.getHeader(REFERER); + if (!isInternalReferer(referer)) { + log.debug("Got external referer, clear session to reauthenticate"); + contextLogoutHandler.logout(req, res, null); + } + } + chain.doFilter(req, res); + } + + private boolean isInternalReferer(String referer) { + if (!StringUtils.hasText(referer)) { + // no referer, consider as internal + return true; + } + + boolean isInternal = referer.startsWith(oidcIssuer); + if (!isInternal) { + if (proxyEnabled) { + // check if referer is PROXY (SP part) + isInternal = referer.startsWith(proxySpEntityId); + } else { + // check if referer is IDP + isInternal = referer.startsWith(idpEntityId); + } + } + + log.debug("Referer {} is internal: {}", referer, isInternal); + return isInternal; + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlProperties.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlProperties.java new file mode 100644 index 000000000..6ccbcfed4 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlProperties.java @@ -0,0 +1,128 @@ +package cz.muni.ics.oidc.saml; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.StringUtils; + +public class SamlProperties implements InitializingBean { + + private static final Logger log = LoggerFactory.getLogger(SamlProperties.class); + + private String entityID; + private String keystoreLocation; + private String keystorePassword; + private String keystoreDefaultKey; + private String keystoreDefaultKeyPassword; + private String defaultIdpEntityId; + private String idpMetadataFile; + private String idpMetadataUrl; + private String[] acrReservedPrefixes; + + public String getEntityID() { + return entityID; + } + + public void setEntityID(String entityID) { + this.entityID = entityID; + } + + public String getKeystoreLocation() { + return keystoreLocation; + } + + public void setKeystoreLocation(String keystoreLocation) { + this.keystoreLocation = keystoreLocation; + } + + public String getKeystorePassword() { + return keystorePassword; + } + + public void setKeystorePassword(String keystorePassword) { + this.keystorePassword = keystorePassword; + } + + public String getKeystoreDefaultKey() { + return keystoreDefaultKey; + } + + public void setKeystoreDefaultKey(String keystoreDefaultKey) { + this.keystoreDefaultKey = keystoreDefaultKey; + } + + public String getKeystoreDefaultKeyPassword() { + return keystoreDefaultKeyPassword; + } + + public void setKeystoreDefaultKeyPassword(String keystoreDefaultKeyPassword) { + this.keystoreDefaultKeyPassword = keystoreDefaultKeyPassword; + } + + public String getDefaultIdpEntityId() { + return defaultIdpEntityId; + } + + public void setDefaultIdpEntityId(String defaultIdpEntityId) { + this.defaultIdpEntityId = defaultIdpEntityId; + } + + public String getIdpMetadataFile() { + return idpMetadataFile; + } + + public void setIdpMetadataFile(String idpMetadataFile) { + this.idpMetadataFile = idpMetadataFile; + } + + public String getIdpMetadataUrl() { + return idpMetadataUrl; + } + + public void setIdpMetadataUrl(String idpMetadataUrl) { + this.idpMetadataUrl = idpMetadataUrl; + } + + @Override + public void afterPropertiesSet() throws Exception { + if (!StringUtils.hasText(idpMetadataUrl) && !StringUtils.hasText(idpMetadataFile)) { + throw new IllegalStateException("No URL nor file provided for metadata"); + } + if (StringUtils.hasText(idpMetadataUrl)) { + try { + new URL(idpMetadataUrl); + return; + } catch (MalformedURLException e) { + log.warn("'{}' is not a valid URL", idpMetadataUrl); + } + } + File f = new File(idpMetadataFile); + if (!f.exists()) { + throw new IllegalStateException("File '" + idpMetadataFile + "' does not exist"); + } + } + + public String[] getAcrReservedPrefixes() { + return acrReservedPrefixes; + } + + public void setAcrReservedPrefixes(String[] acrReservedPrefixes) { + if (acrReservedPrefixes == null) { + this.acrReservedPrefixes = new String[] {}; + } else { + List<String> nonNull = new ArrayList<>(); + for (String prefix: acrReservedPrefixes) { + if (StringUtils.hasText(prefix)) { + nonNull.add(prefix); + } + } + + this.acrReservedPrefixes = nonNull.toArray(new String[0]); + } + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/AttributeMappingsService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/AttributeMappingsService.java new file mode 100644 index 000000000..e9f3de3b1 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/AttributeMappingsService.java @@ -0,0 +1,120 @@ +package cz.muni.ics.oidc.server; + + +import cz.muni.ics.oidc.models.AttributeMapping; +import cz.muni.ics.oidc.models.enums.PerunAttrValueType; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Service providing methods to use AttributeMapping objects when fetching attributes. + * + * Names for the attribute are configured in configuration file in the following way: + * (replace [entity] with one of user|vo|facility|resource|group) + * <ul> + * <li><b>[entity].attribute_names.customList</b> - comma separated list of names for attributes</li> + * </ul> + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class AttributeMappingsService { + + private static final Logger log = LoggerFactory.getLogger(AttributeMappingsService.class); + + private static final String LDAP_NAME = ".mapping.ldap"; + private static final String RPC_NAME = ".mapping.rpc"; + private static final String TYPE = ".type"; + private static final String SEPARATOR = ".separator"; + + private final Map<String, AttributeMapping> attributeMap; + + public AttributeMappingsService(String[] attrIdentifiersFixed, String[] attrIdentifiersCustom, + Properties attrMappingsProperties) { + attributeMap = new HashMap<>(); + + if (attrIdentifiersFixed != null) { + this.initAttrMappings(attrIdentifiersFixed, attrMappingsProperties); + } + + if (attrIdentifiersCustom != null) { + this.initAttrMappings(attrIdentifiersCustom, attrMappingsProperties); + } + } + + /** + * Get AttributeMapping based on the given internal identifier of attribute. + * @param identifier String identifier of the attribute. + * @return AttributeMapping. If invalid identifier is passed (null or unknown) an exception is thrown. + */ + public AttributeMapping getMappingByIdentifier(String identifier) { + if (identifier == null) { + throw new IllegalArgumentException("Identifier cannot be null"); + } else if (!attributeMap.containsKey(identifier)) { + return null; + } + + return attributeMap.get(identifier); + } + + /** + * Get Set of AttributeMapping based on the given internal identifiers of attributes. + * @param identifiers Collection of Strings + * @return Set of AttributeMapping. If invalid identifier is passed inside the collection, this identifier is ignored. + */ + public Set<AttributeMapping> getMappingsByIdentifiers(Collection<String> identifiers) { + Set<AttributeMapping> mappings = new HashSet<>(); + if (identifiers != null) { + for (String identifier : identifiers) { + try { + mappings.add(getMappingByIdentifier(identifier)); + } catch (IllegalArgumentException e) { + log.warn("Caught {} when getting mappings, check your configuration for identifier {}", + e.getClass(), identifier, e); + } + } + } + + return mappings.stream().filter(Objects::nonNull).collect(Collectors.toSet()); + } + + private void initAttrMappings(String[] attributeIdentifiers, Properties attrProperties) { + if (attributeIdentifiers == null || attributeIdentifiers.length <= 0) { + return; + } + + for (String identifier : attributeIdentifiers) { + if (identifier == null || identifier.isEmpty()) { + continue; + } + AttributeMapping am = initAttrMapping(identifier, attrProperties); + log.debug("Initialized attributeMapping: {}", am); + attributeMap.put(am.getIdentifier(), am); + } + } + + private AttributeMapping initAttrMapping(String attrIdentifier, Properties attrProperties) { + String rpcIdentifier = attrProperties.getProperty(attrIdentifier + RPC_NAME); + String ldapIdentifier = attrProperties.getProperty(attrIdentifier + LDAP_NAME); + if (ldapIdentifier != null && ldapIdentifier.trim().isEmpty()) { + ldapIdentifier = null; + } + + String type = attrProperties.getProperty(attrIdentifier + TYPE); + String separator = ""; + if (PerunAttrValueType.MAP_KEY_VALUE.equals(PerunAttrValueType.parse(type))) { + separator = attrProperties.getProperty(attrIdentifier + SEPARATOR); + } + + return new AttributeMapping(attrIdentifier, rpcIdentifier, ldapIdentifier, type, separator); + } + +} + diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/CustomClearTasks.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/CustomClearTasks.java new file mode 100644 index 000000000..82efdf218 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/CustomClearTasks.java @@ -0,0 +1,172 @@ +package cz.muni.ics.oidc.server; + +import java.time.Instant; +import java.util.Date; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.Query; +import javax.persistence.QueryTimeoutException; +import cz.muni.ics.oauth2.model.AuthorizationCodeEntity; +import cz.muni.ics.oauth2.model.DeviceCode; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; +import cz.muni.ics.openid.connect.models.Acr; +import cz.muni.ics.openid.connect.models.DeviceCodeAcr; +import org.springframework.stereotype.Repository; + +@Repository +public class CustomClearTasks { + + @PersistenceContext(unitName = "defaultPersistenceUnit") + private EntityManager manager; + + public int clearExpiredTokens(long timeout) { + int count = 0; + count += this.clearExpiredAccessTokens(timeout); + count += this.clearExpiredRefreshTokens(timeout); + count += this.clearOrphanedAuthHolders(timeout); + return count; + } + + int clearExpiredAccessTokens(long timeout) { + manager.flush(); + manager.clear(); + int count = 0; + Query query1 = manager.createQuery("DELETE FROM OAuth2AccessTokenEntity a " + + "WHERE a.expiration <= :" + OAuth2AccessTokenEntity.PARAM_DATE); + query1.setParameter(OAuth2AccessTokenEntity.PARAM_DATE, new Date()); + if (timeout > 0) { + query1.setHint("javax.persistence.query.timeout", timeout); + } + try { + count += query1.executeUpdate(); + } catch (QueryTimeoutException e) { + // this is OK + } + return count; + } + + int clearExpiredRefreshTokens(long timeout) { + manager.flush(); + manager.clear(); + int count = 0; + Query query2 = manager.createQuery("DELETE FROM OAuth2RefreshTokenEntity r " + + "WHERE r.expiration <= :" + OAuth2RefreshTokenEntity.PARAM_DATE); + query2.setParameter(OAuth2RefreshTokenEntity.PARAM_DATE, new Date()); + if (timeout > 0) { + query2.setHint("javax.persistence.query.timeout", timeout); + } + try { + count += query2.executeUpdate(); + } catch (QueryTimeoutException e) { + // this is OK + } + return count; + } + + int clearOrphanedAuthHolders(long timeout) { + manager.flush(); + manager.clear(); + int count = 0; + Query query3 = manager.createQuery("DELETE FROM AuthenticationHolderEntity a " + + "WHERE a.id NOT IN (SELECT t.authenticationHolder.id FROM OAuth2AccessTokenEntity t) AND " + + "a.id NOT IN (SELECT r.authenticationHolder.id FROM OAuth2RefreshTokenEntity r) AND " + + "a.id NOT IN (SELECT c.authenticationHolder.id FROM AuthorizationCodeEntity c)"); + if (timeout > 0) { + query3.setHint("javax.persistence.query.timeout", timeout); + } + try { + count += query3.executeUpdate(); + } catch (QueryTimeoutException e) { + // this is OK + } + return count; + } + + public int clearExpiredSites(long timeout) { + manager.flush(); + manager.clear(); + int count = 0; + Query query = manager.createQuery("DELETE FROM ApprovedSite a WHERE a.timeoutDate <= :date"); + query.setParameter("date", new Date()); + if (timeout > 0) { + query.setHint("javax.persistence.query.timeout", timeout); + } + try { + count += query.executeUpdate(); + } catch (QueryTimeoutException e) { + // this is OK + } + return count; + } + + public int clearExpiredAuthorizationCodes(long timeout) { + manager.flush(); + manager.clear(); + int count = 0; + Query query = manager.createQuery("DELETE FROM AuthorizationCodeEntity a " + + "WHERE a.expiration <= :" + AuthorizationCodeEntity.PARAM_DATE); + query.setParameter(AuthorizationCodeEntity.PARAM_DATE, new Date()); + if (timeout > 0) { + query.setHint("javax.persistence.query.timeout", timeout); + } + try { + count += query.executeUpdate(); + } catch (QueryTimeoutException e) { + // this is OK + } + return count; + } + + public int clearExpiredDeviceCodes(long timeout) { + manager.flush(); + manager.clear(); + int count = 0; + Query query = manager.createQuery("DELETE FROM DeviceCode d WHERE d.expiration <= :" + DeviceCode.PARAM_DATE); + query.setParameter(DeviceCode.PARAM_DATE, new Date()); + if (timeout > 0) { + query.setHint("javax.persistence.query.timeout", timeout); + } + try { + count += query.executeUpdate(); + } catch (QueryTimeoutException e) { + // this is OK + } + return count; + } + + public int clearExpiredAcrs(long timeout) { + manager.flush(); + manager.clear(); + int count = 0; + Query query = manager.createNamedQuery(Acr.DELETE_EXPIRED); + query.setParameter(Acr.PARAM_EXPIRES_AT, Instant.now().toEpochMilli()); + if (timeout > 0) { + query.setHint("javax.persistence.query.timeout", timeout); + } + try { + count += query.executeUpdate(); + } catch (QueryTimeoutException e) { + // this is OK + } + return count; + } + + public int clearExpiredDeviceCodeAcrs(long timeout) { + manager.flush(); + manager.clear(); + int count = 0; + Query query = manager.createNamedQuery(DeviceCodeAcr.DELETE_EXPIRED); + query.setParameter(DeviceCodeAcr.PARAM_EXPIRES_AT, Instant.now().toEpochMilli()); + if (timeout > 0) { + query.setHint("javax.persistence.query.timeout", timeout); + } + try { + count += query.executeUpdate(); + } catch (QueryTimeoutException e) { + // this is OK + } + return count; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/CustomTaskScheduler.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/CustomTaskScheduler.java new file mode 100644 index 000000000..3d29523ca --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/CustomTaskScheduler.java @@ -0,0 +1,140 @@ +package cz.muni.ics.oidc.server; + +import java.util.concurrent.TimeUnit; +import javax.sql.DataSource; +import net.javacrumbs.shedlock.core.LockAssert; +import net.javacrumbs.shedlock.core.LockProvider; +import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider; +import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock; +import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.transaction.annotation.Transactional; + +/** + * A custom scheduler for tasks with usage of ShedLock. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@Configuration +@EnableScheduling +@EnableSchedulerLock(defaultLockAtMostFor = "30s") +public class CustomTaskScheduler { + + private static final long ONE_MINUTE = 60000L; + + private static final Logger log = LoggerFactory.getLogger(CustomTaskScheduler.class); + + private final CustomClearTasks customClearTasks; + private final DataSource dataSource; + + @Autowired + public CustomTaskScheduler(CustomClearTasks customClearTasks, + @Qualifier("dataSource") DataSource dataSource) + { + this.customClearTasks = customClearTasks; + this.dataSource = dataSource; + } + + @Bean + public LockProvider lockProvider() { + return new JdbcTemplateLockProvider(this.dataSource); + } + + @Transactional(value = "defaultTransactionManager") + @Scheduled(fixedDelay = 60 * ONE_MINUTE, initialDelay = ONE_MINUTE) + @SchedulerLock(name = "clearExpiredSites", lockAtMostFor = "3590s", lockAtLeastFor = "3590s") + public void clearExpiredSites() { + try { + LockAssert.assertLocked(); + } catch (IllegalArgumentException e) { + return; + } + long start = System.currentTimeMillis(); + int count = this.customClearTasks.clearExpiredSites(TimeUnit.MINUTES.toMillis(15)); + long execution = System.currentTimeMillis() - start; + log.info("clearExpiredSites took {}ms, deleted {} records", execution, count); + } + + @Transactional(value = "defaultTransactionManager") + @Scheduled(fixedDelay = 60 * ONE_MINUTE, initialDelay = 12 * ONE_MINUTE) + @SchedulerLock(name = "clearExpiredTokens", lockAtMostFor = "3590s", lockAtLeastFor = "3590s") + public void clearExpiredTokens() { + try { + LockAssert.assertLocked(); + } catch (IllegalArgumentException e) { + return; + } + long start = System.currentTimeMillis(); + int count = this.customClearTasks.clearExpiredTokens(TimeUnit.MINUTES.toMillis(15)); + long execution = System.currentTimeMillis() - start; + log.info("clearExpiredTokens took {}ms, deleted {} records", execution, count); + } + + @Transactional(value = "defaultTransactionManager") + @Scheduled(fixedDelay = 60 * ONE_MINUTE, initialDelay = 24 * ONE_MINUTE) + @SchedulerLock(name = "clearExpiredAuthorizationCodes", lockAtMostFor = "3590s", lockAtLeastFor = "3590s") + public void clearExpiredAuthorizationCodes() { + try { + LockAssert.assertLocked(); + } catch (IllegalArgumentException e) { + return; + } + long start = System.currentTimeMillis(); + int count = this.customClearTasks.clearExpiredAuthorizationCodes(TimeUnit.MINUTES.toMillis(15)); + long execution = System.currentTimeMillis() - start; + log.info("clearExpiredAuthorizationCodes took {}ms, deleted {} records", execution, count); + } + + @Transactional(value = "defaultTransactionManager") + @Scheduled(fixedDelay = 60 * ONE_MINUTE, initialDelay = 36 * ONE_MINUTE) + @SchedulerLock(name = "clearExpiredDeviceCodes", lockAtMostFor = "3590s", lockAtLeastFor = "3590s") + public void clearExpiredDeviceCodes() { + try { + LockAssert.assertLocked(); + } catch (IllegalArgumentException e) { + return; + } + long start = System.currentTimeMillis(); + int count = this.customClearTasks.clearExpiredDeviceCodes(TimeUnit.MINUTES.toMillis(15)); + long execution = System.currentTimeMillis() - start; + log.info("clearExpiredDeviceCodes took {}ms, deleted {} records", execution, count); + } + + @Transactional(value = "defaultTransactionManager") + @Scheduled(fixedDelay = 60 * ONE_MINUTE, initialDelay = 48 * ONE_MINUTE) + @SchedulerLock(name = "clearExpiredAcrs", lockAtMostFor = "3590s", lockAtLeastFor = "3590s") + public void clearExpiredAcrs() { + try { + LockAssert.assertLocked(); + } catch (IllegalArgumentException e) { + return; + } + long start = System.currentTimeMillis(); + int count = this.customClearTasks.clearExpiredAcrs(TimeUnit.MINUTES.toMillis(15)); + long execution = System.currentTimeMillis() - start; + log.info("clearExpiredAcrs took {}ms, deleted {} records", execution, count); + } + + @Transactional(value = "defaultTransactionManager") + @Scheduled(fixedDelay = 60 * ONE_MINUTE, initialDelay = 48 * ONE_MINUTE) + @SchedulerLock(name = "clearExpiredDeviceAcrs", lockAtMostFor = "3590s", lockAtLeastFor = "3590s") + public void clearExpiredDeviceAcrs() { + try { + LockAssert.assertLocked(); + } catch (IllegalArgumentException e) { + return; + } + long start = System.currentTimeMillis(); + int count = this.customClearTasks.clearExpiredAcrs(TimeUnit.MINUTES.toMillis(15)); + long execution = System.currentTimeMillis() - start; + log.info("clearExpiredDeviceAcrs took {}ms, deleted {} records", execution, count); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunAccessTokenEnhancer.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunAccessTokenEnhancer.java new file mode 100644 index 000000000..ed49df033 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunAccessTokenEnhancer.java @@ -0,0 +1,163 @@ +package cz.muni.ics.oidc.server; + +import static cz.muni.ics.oauth2.service.IntrospectionResultAssembler.SCOPE; +import static cz.muni.ics.oauth2.service.IntrospectionResultAssembler.SCOPE_SEPARATOR; + +import com.google.common.base.Joiner; +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.nimbusds.jose.JOSEObjectType; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jwt.JWT; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import java.util.Date; +import java.util.UUID; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.service.OIDCTokenService; +import cz.muni.ics.openid.connect.service.UserInfoService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.OAuth2Request; +import org.springframework.security.oauth2.provider.token.TokenEnhancer; + +/** + * Copy of ConnectTokenEnhancer. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class PerunAccessTokenEnhancer implements TokenEnhancer { + + private final static Logger log = LoggerFactory.getLogger(PerunAccessTokenEnhancer.class); + + private final ConfigurationPropertiesBean configBean; + private final JWTSigningAndValidationService jwtService; + private final ClientDetailsEntityService clientService; + private final UserInfoService userInfoService; + private final OIDCTokenService connectTokenService; + + private AccessTokenClaimsModifier accessTokenClaimsModifier; + + @Autowired + public PerunAccessTokenEnhancer(ConfigurationPropertiesBean configBean, + JWTSigningAndValidationService jwtService, + ClientDetailsEntityService clientService, + UserInfoService userInfoService, + OIDCTokenService connectTokenService) + { + this.configBean = configBean; + this.jwtService = jwtService; + this.clientService = clientService; + this.userInfoService = userInfoService; + this.connectTokenService = connectTokenService; + } + + public void setAccessTokenClaimsModifier(AccessTokenClaimsModifier accessTokenClaimsModifier) { + this.accessTokenClaimsModifier = accessTokenClaimsModifier; + } + + /** + * Exact copy from ConnectTokenEnhancer with added hooks. + */ + @Override + public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { + Date iat = new Date(); + OAuth2AccessTokenEntity token = (OAuth2AccessTokenEntity) accessToken; + OAuth2Request originalAuthRequest = authentication.getOAuth2Request(); + + String clientId = originalAuthRequest.getClientId(); + ClientDetailsEntity client = clientService.loadClientByClientId(clientId); + + UserInfo userInfo = null; + if (originalAuthRequest.getScope().contains(SystemScopeService.OPENID_SCOPE) + && !authentication.isClientOnly()) { + userInfo = userInfoService.getByUsernameAndClientId(authentication.getName(), clientId); + } + + // create signed access token + String sub = userInfo != null ? userInfo.getSub() : authentication.getName(); + JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder() + .claim("azp", clientId) + .issuer(configBean.getIssuer()) + .issueTime(iat) + .expirationTime(token.getExpiration()) + .subject(sub) + .claim(SCOPE, Joiner.on(SCOPE_SEPARATOR).join(accessToken.getScope())) + .jwtID(UUID.randomUUID().toString()); // set a random NONCE in the middle of it + accessTokenClaimsHook(sub, builder, accessToken, authentication, userInfo); + + String audience = (String) authentication.getOAuth2Request().getExtensions().get("aud"); + if (!Strings.isNullOrEmpty(audience)) { + builder.audience(Lists.newArrayList(audience)); + } + + JWTClaimsSet claims = builder.build(); + + JWSAlgorithm signingAlg = jwtService.getDefaultSigningAlgorithm(); + JWSHeader header = new JWSHeader(signingAlg, JOSEObjectType.JWT, null, null, null, null, null, null, null, null, + jwtService.getDefaultSignerKeyId(), true, null, null); + SignedJWT signed = new SignedJWT(header, claims); + + jwtService.signJwt(signed); + token.setJwt(signed); + + if (userInfo != null) { + //needs access token + JWT idToken = connectTokenService.createIdToken(client, originalAuthRequest, iat, userInfo.getSub(), token); + // attach the id token to the parent access token + token.setIdToken(idToken); + if (log.isDebugEnabled()) log.debug("idToken: {}", idToken.serialize()); + } else { + // can't create an id token if we can't find the user + log.warn("Request for ID token when no user is present."); + } + + this.logHook(token, authentication); + return token; + } + + private void logHook(OAuth2AccessTokenEntity token, OAuth2Authentication authentication) { + //log request info from authentication + Object principal = authentication.getPrincipal(); + String userId = principal instanceof User ? ((User) principal).getUsername() : principal.toString(); + OAuth2Request oAuth2Request = authentication.getOAuth2Request(); + log.info("userId: {}, clientId: {}, grantType: {}, redirectUri: {}, scopes: {}", + userId, oAuth2Request.getClientId(), oAuth2Request.getGrantType(), oAuth2Request.getRedirectUri(), token.getScope()); + if (log.isDebugEnabled()) log.debug("access token: {}", token.getValue()); + } + + private void accessTokenClaimsHook(String sub, JWTClaimsSet.Builder builder, OAuth2AccessToken accessToken, + OAuth2Authentication authentication, UserInfo userInfo) + { + if (accessTokenClaimsModifier != null) { + accessTokenClaimsModifier.modifyClaims(sub, builder, accessToken, authentication, userInfo); + } + } + + @FunctionalInterface + public interface AccessTokenClaimsModifier { + void modifyClaims(String sub, JWTClaimsSet.Builder builder, OAuth2AccessToken accessToken, + OAuth2Authentication authentication, UserInfo userInfo); + } + + public static class NoOpAccessTokenClaimsModifier implements AccessTokenClaimsModifier { + @Override + public void modifyClaims(String sub, JWTClaimsSet.Builder builder, OAuth2AccessToken accessToken, + OAuth2Authentication authentication, UserInfo userInfo) + { + log.debug("no modification"); + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunAcrRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunAcrRepository.java new file mode 100644 index 000000000..5721bb477 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunAcrRepository.java @@ -0,0 +1,81 @@ +package cz.muni.ics.oidc.server; + +import java.time.Instant; +import javax.persistence.EntityManager; +import javax.persistence.NoResultException; +import javax.persistence.PersistenceContext; +import javax.persistence.Query; +import javax.persistence.TypedQuery; +import cz.muni.ics.openid.connect.models.Acr; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +/** + * Repository class for ACR model. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@Repository +@Transactional(value = "defaultTransactionManager") +public class PerunAcrRepository { + + @PersistenceContext(unitName = "defaultPersistenceUnit") + private EntityManager manager; + + public Acr getActive(String sub, String clientId, String state) { + TypedQuery<Acr> query = manager.createNamedQuery(Acr.GET_ACTIVE, Acr.class); + query.setParameter(Acr.PARAM_SUB, sub); + query.setParameter(Acr.PARAM_CLIENT_ID, clientId); + query.setParameter(Acr.PARAM_STATE, state); + query.setParameter(Acr.PARAM_EXPIRES_AT, now()); + try { + return query.getSingleResult(); + } catch (NoResultException e) { + return null; + } + } + + public Acr getById(Long id) { + TypedQuery<Acr> query = manager.createNamedQuery(Acr.GET_BY_ID, Acr.class); + query.setParameter(Acr.PARAM_ID, id); + query.setParameter(Acr.PARAM_EXPIRES_AT, now()); + + try { + return query.getSingleResult(); + } catch (NoResultException e) { + return null; + } + } + + @Transactional + public Acr store(Acr acr) { + Acr existing = getActive(acr.getSub(), acr.getClientId(), acr.getState()); + if (existing != null) { + return existing; + } else { + Acr tmp = manager.merge(acr); + manager.flush(); + return tmp; + } + } + + @Transactional + public void remove(Long id) { + Acr acr = getById(id); + if (acr != null) { + manager.remove(acr); + } + } + + @Transactional + public void deleteExpired() { + Query query = manager.createNamedQuery(Acr.DELETE_EXPIRED); + query.setParameter(Acr.PARAM_EXPIRES_AT, now()); + query.executeUpdate(); + } + + private long now() { + return Instant.now().toEpochMilli(); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunDeviceCodeAcrRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunDeviceCodeAcrRepository.java new file mode 100644 index 000000000..bcb2d05b8 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunDeviceCodeAcrRepository.java @@ -0,0 +1,91 @@ +package cz.muni.ics.oidc.server; + +import java.time.Instant; +import javax.persistence.EntityManager; +import javax.persistence.NoResultException; +import javax.persistence.PersistenceContext; +import javax.persistence.Query; +import javax.persistence.TypedQuery; +import cz.muni.ics.openid.connect.models.Acr; +import cz.muni.ics.openid.connect.models.DeviceCodeAcr; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +/** + * Repository class for ACR model. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@Repository +@Transactional(value = "defaultTransactionManager") +public class PerunDeviceCodeAcrRepository { + + @PersistenceContext(unitName = "defaultPersistenceUnit") + private EntityManager manager; + + public DeviceCodeAcr getActiveByDeviceCode(String deviceCode) { + TypedQuery<DeviceCodeAcr> query = manager.createNamedQuery(DeviceCodeAcr.GET_ACTIVE_BY_DEVICE_CODE, + DeviceCodeAcr.class); + query.setParameter(DeviceCodeAcr.PARAM_DEVICE_CODE, deviceCode); + query.setParameter(Acr.PARAM_EXPIRES_AT, now()); + try { + return query.getSingleResult(); + } catch (NoResultException e) { + return null; + } + } + + public DeviceCodeAcr getByUserCode(String userCode) { + TypedQuery<DeviceCodeAcr> query = manager.createNamedQuery(DeviceCodeAcr.GET_BY_USER_CODE, DeviceCodeAcr.class); + query.setParameter(DeviceCodeAcr.PARAM_USER_CODE, userCode); + + try { + return query.getSingleResult(); + } catch (NoResultException e) { + return null; + } + } + + public DeviceCodeAcr getById(Long id) { + TypedQuery<DeviceCodeAcr> query = manager.createNamedQuery(DeviceCodeAcr.GET_BY_ID, DeviceCodeAcr.class); + query.setParameter(DeviceCodeAcr.PARAM_ID, id); + query.setParameter(DeviceCodeAcr.PARAM_EXPIRES_AT, now()); + + try { + return query.getSingleResult(); + } catch (NoResultException e) { + return null; + } + } + + @Transactional + public DeviceCodeAcr store(DeviceCodeAcr acr) { + try { + return getActiveByDeviceCode(acr.getDeviceCode()); + } catch (NoResultException e) { + DeviceCodeAcr tmp = manager.merge(acr); + manager.flush(); + return tmp; + } + } + + @Transactional + public void remove(Long id) { + DeviceCodeAcr acr = getById(id); + if (acr != null) { + manager.remove(acr); + } + } + + @Transactional + public void deleteExpired() { + Query query = manager.createNamedQuery(DeviceCodeAcr.DELETE_EXPIRED); + query.setParameter(DeviceCodeAcr.PARAM_EXPIRES_AT, now()); + query.executeUpdate(); + } + + private long now() { + return Instant.now().toEpochMilli(); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunIntrospectionResultAssembler.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunIntrospectionResultAssembler.java new file mode 100644 index 000000000..b132fe64c --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunIntrospectionResultAssembler.java @@ -0,0 +1,65 @@ +package cz.muni.ics.oidc.server; + +import com.google.common.collect.Sets; +import com.google.gson.JsonElement; +import java.util.Map; +import java.util.Set; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.service.impl.DefaultIntrospectionResultAssembler; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.service.ScopeClaimTranslationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Assembler of result obtained from introspection endpoint. + * Adds "iss" to identify issuer in response from Introspection endpoint to Resource Server. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class PerunIntrospectionResultAssembler extends DefaultIntrospectionResultAssembler { + + private final static Logger log = LoggerFactory.getLogger(PerunIntrospectionResultAssembler.class); + + private final ConfigurationPropertiesBean configBean; + private final ScopeClaimTranslationService translator; + + public PerunIntrospectionResultAssembler(ConfigurationPropertiesBean configBean, + ScopeClaimTranslationService translator) + { + this.configBean = configBean; + this.translator = translator; + } + + @Override + public Map<String, Object> assembleFrom(OAuth2AccessTokenEntity accessToken, UserInfo userInfo, + Set<String> resourceServerScopes) + { + log.info("adding claims at Introspection endpoint for client {}({}) and user {}({})", + accessToken.getClient().getClientId(), accessToken.getClient().getClientName(), userInfo.getSub(), + userInfo.getName()); + Map<String, Object> map = super.assembleFrom(accessToken, userInfo, resourceServerScopes); + Set<String> accessTokenScopes = accessToken.getScope(); + Set<String> scopes = Sets.intersection(resourceServerScopes, accessTokenScopes); + log.debug("resource server scopes: {}", resourceServerScopes); + log.debug("access token scopes : {}", accessTokenScopes); + log.debug("common scopes : {}", scopes); + this.addDataToResponse(map, userInfo, scopes); + return map; + } + + private void addDataToResponse(Map<String, Object> map, UserInfo userInfo, Set<String> scopes) { + log.debug("adding iss to introspection response {}", map); + map.put("iss", configBean.getIssuer()); + log.debug("adding user claims"); + Set<String> authorizedClaims = translator.getClaimsForScopeSet(scopes); + for (Map.Entry<String, JsonElement> claim : userInfo.toJson().entrySet()) { + if (authorizedClaims.contains(claim.getKey()) && claim.getValue() != null && !claim.getValue().isJsonNull()) { + log.debug("adding claim {} with value {}", claim.getKey(), claim.getValue()); + map.put(claim.getKey(), claim.getValue()); + } + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunOIDCTokenService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunOIDCTokenService.java new file mode 100644 index 000000000..44fda4266 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunOIDCTokenService.java @@ -0,0 +1,124 @@ +package cz.muni.ics.oidc.server; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.nimbusds.jose.util.JSONObjectUtils; +import com.nimbusds.jwt.JWTClaimsSet; +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import java.text.ParseException; +import java.util.Map; +import java.util.Set; +import net.minidev.json.JSONArray; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.openid.connect.service.ScopeClaimTranslationService; +import cz.muni.ics.openid.connect.service.UserInfoService; +import cz.muni.ics.openid.connect.service.impl.DefaultOIDCTokenService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.oauth2.provider.OAuth2Request; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +/** + * Modifies ID Token. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class PerunOIDCTokenService extends DefaultOIDCTokenService { + + private static final Logger log = LoggerFactory.getLogger(PerunOIDCTokenService.class); + + public static final String SESSION_PARAM_ACR = "acr"; + + private final UserInfoService userInfoService; + private final ScopeClaimTranslationService translator; + private final PerunOidcConfig perunOidcConfig; + + private final Gson gson = new Gson(); + + @Autowired + public PerunOIDCTokenService(UserInfoService userInfoService, + ScopeClaimTranslationService translator, + PerunOidcConfig perunOidcConfig) + { + this.userInfoService = userInfoService; + this.translator = translator; + this.perunOidcConfig = perunOidcConfig; + } + + @Override + protected void addCustomIdTokenClaims(JWTClaimsSet.Builder idClaims, ClientDetailsEntity client, OAuth2Request request, + String sub, OAuth2AccessTokenEntity accessToken) + { + log.debug("modifying ID token"); + String userId = accessToken.getAuthenticationHolder().getAuthentication().getName(); + String clientId = request.getClientId(); + log.debug("userId={},clientId={}", userId, clientId); + + Set<String> scopes = accessToken.getScope(); + Set<String> authorizedClaims = translator.getClaimsForScopeSet(scopes); + Set<String> idTokenClaims = translator.getClaimsForScopeSet(perunOidcConfig.getIdTokenScopes()); + + for (Map.Entry<String, JsonElement> claim : userInfoService.getByUsernameAndClientId(userId, + clientId).toJson().entrySet()) { + String claimKey = claim.getKey(); + JsonElement claimValue = claim.getValue(); + if (claimValue != null && !claimValue.isJsonNull() && authorizedClaims.contains(claimKey) + && idTokenClaims.contains(claimKey)) + { + log.debug("adding to ID token claim {} with value {}", claimKey, claimValue); + idClaims.claim(claimKey, gson2jsonsmart(claimValue)); + } + } + + String acr = getAuthnContextClass(); + if (acr != null) { + log.debug("adding to ID token claim acr with value {}", acr); + idClaims.claim("acr", acr); + } + } + + private String getAuthnContextClass() { + ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + return (String) attr.getAttribute(SESSION_PARAM_ACR, RequestAttributes.SCOPE_SESSION); + } + + /** + * Converts claim values from com.google.gson.JsonElement to net.minidev.json.JSONObject or primitive value + * + * @param jsonElement Gson representation + * @return json-smart representation + */ + private Object gson2jsonsmart(JsonElement jsonElement) { + if (jsonElement.isJsonPrimitive()) { + JsonPrimitive p = jsonElement.getAsJsonPrimitive(); + if (p.isString()) { + return p.getAsString(); + } else if (p.isBoolean()) { + return p.getAsBoolean(); + } else if (p.isNumber()) { + return p.getAsNumber(); + } else { + log.warn("unknown JsonPrimitive {}", p); + return null; + } + } else if (jsonElement.isJsonObject()) { + try { + return JSONObjectUtils.parse(gson.toJson(jsonElement)); + } catch (ParseException e) { + log.error("cannot convert Gson->smart-json.JSONObject", e); + return null; + } + } else if (jsonElement.isJsonArray()) { + JSONArray jsonArray = new JSONArray(); + jsonElement.getAsJsonArray().forEach(je -> jsonArray.appendElement(gson2jsonsmart(je))); + return jsonArray; + } else { + return null; + } + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunPrincipal.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunPrincipal.java new file mode 100644 index 000000000..03574f498 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunPrincipal.java @@ -0,0 +1,35 @@ +package cz.muni.ics.oidc.server; + +/** + * Principal specific for Perun user. User is identified by login (extLogin) and name + * of the external source (extSourceName) he/she used for login (usually identity provider). + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class PerunPrincipal { + + private final String extLogin; + private final String extSourceName; + + public PerunPrincipal(String extLogin, String extSourceName) { + this.extLogin = extLogin; + this.extSourceName = extSourceName; + } + + public String getExtLogin() { + return extLogin; + } + + public String getExtSourceName() { + return extSourceName; + } + + @Override + public String toString() { + return "PerunPrincipal{" + + "extLogin='" + extLogin + '\'' + + ", extSourceName='" + extSourceName + '\'' + + '}'; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunScopeClaimTranslationService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunScopeClaimTranslationService.java new file mode 100644 index 000000000..4a65c6961 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/PerunScopeClaimTranslationService.java @@ -0,0 +1,88 @@ +package cz.muni.ics.oidc.server; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.SetMultimap; +import cz.muni.ics.oidc.server.claims.PerunCustomClaimDefinition; +import cz.muni.ics.oidc.server.userInfo.PerunUserInfoService; +import java.util.HashSet; +import java.util.Set; +import cz.muni.ics.openid.connect.service.ScopeClaimTranslationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Translates scopes to claims. A single scope can provide access to multiple claims. + * Set this as spring bean named "scopeClaimTranslator". This code is copied from class + * cz.muni.ics.openid.connect.service.impl.DefaultScopeClaimTranslationService + * which for some reason is not accessible in this project, and extended. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class PerunScopeClaimTranslationService implements ScopeClaimTranslationService { + + private final static Logger log = LoggerFactory.getLogger(PerunScopeClaimTranslationService.class); + + public static final String OPENID = "openid"; + public static final String PROFILE = "profile"; + public static final String EMAIL = "email"; + public static final String PHONE = "phone"; + public static final String ADDRESS = "address"; + + private final SetMultimap<String, String> scopesToClaims = HashMultimap.create(); + + public void setPerunUserInfoService(PerunUserInfoService perunUserInfoService) { + for(PerunCustomClaimDefinition pccd : perunUserInfoService.getCustomClaims()) { + log.info("adding custom claim \"{}\" in scope \"{}\" ",pccd.getClaim(),pccd.getScope()); + scopesToClaims.put(pccd.getScope(),pccd.getClaim()); + } + } + + /** + * Default constructor; initializes scopesToClaims map + */ + public PerunScopeClaimTranslationService() { + scopesToClaims.put(OPENID, "sub"); + + scopesToClaims.put(PROFILE, "name"); + scopesToClaims.put(PROFILE, "preferred_username"); + scopesToClaims.put(PROFILE, "given_name"); + scopesToClaims.put(PROFILE, "family_name"); + scopesToClaims.put(PROFILE, "middle_name"); + scopesToClaims.put(PROFILE, "nickname"); + scopesToClaims.put(PROFILE, "profile"); + scopesToClaims.put(PROFILE, "picture"); + scopesToClaims.put(PROFILE, "website"); + scopesToClaims.put(PROFILE, "gender"); + scopesToClaims.put(PROFILE, "zoneinfo"); + scopesToClaims.put(PROFILE, "locale"); + scopesToClaims.put(PROFILE, "updated_at"); + scopesToClaims.put(PROFILE, "birthdate"); + + scopesToClaims.put(EMAIL, "email"); + scopesToClaims.put(EMAIL, "email_verified"); + + scopesToClaims.put(PHONE, "phone_number"); + scopesToClaims.put(PHONE, "phone_number_verified"); + + scopesToClaims.put(ADDRESS, "address"); + } + + @Override + public Set<String> getClaimsForScope(String scope) { + if (scopesToClaims.containsKey(scope)) { + return scopesToClaims.get(scope); + } else { + return new HashSet<>(); + } + } + + @Override + public Set<String> getClaimsForScopeSet(Set<String> scopes) { + Set<String> result = new HashSet<>(); + for (String scope : scopes) { + result.addAll(getClaimsForScope(scope)); + } + return result; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapter.java new file mode 100644 index 000000000..817333820 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapter.java @@ -0,0 +1,94 @@ +package cz.muni.ics.oidc.server.adapters; + +import java.util.Collections; +import java.util.Set; + +/** + * Interface for getting data from Perun interfaces. + * Used for fetching necessary data about users, services etc. + * + * @author Martin Kuba <makub@ics.muni.cz> + * @author Dominik František Bučík <bucik@ics.muni.cz> + * @author Peter Jancus <jancus@ics.muni.cz> + */ +public abstract class PerunAdapter implements PerunAdapterMethods { + + private PerunAdapterMethods adapterPrimary; + private PerunAdapterMethods adapterFallback; + private PerunAdapterMethodsRpc adapterRpc; + private PerunAdapterMethodsLdap adapterLdap; + + private boolean callFallback; + + public PerunAdapterMethods getAdapterPrimary() { + return adapterPrimary; + } + + public void setAdapterPrimary(PerunAdapterMethods adapterPrimary) { + this.adapterPrimary = adapterPrimary; + } + + public PerunAdapterMethods getAdapterFallback() { + return adapterFallback; + } + + public void setAdapterFallback(PerunAdapterMethods adapterFallback) { + this.adapterFallback = adapterFallback; + } + + public PerunAdapterMethodsRpc getAdapterRpc() { + return adapterRpc; + } + + public void setAdapterRpc(PerunAdapterMethodsRpc adapterRpc) { + this.adapterRpc = adapterRpc; + } + + public PerunAdapterMethodsLdap getAdapterLdap() { + return adapterLdap; + } + + public void setAdapterLdap(PerunAdapterMethodsLdap adapterLdap) { + this.adapterLdap = adapterLdap; + } + + public boolean isCallFallback() { + return callFallback; + } + + public void setCallFallback(boolean callFallback) { + this.callFallback = callFallback; + } + + public static boolean decideAccess(Set<Long> foundVoIds, Set<Long> foundGroupIds, Set<Long> mandatoryVos, + Set<Long> mandatoryGroups, Set<Long> envVos, Set<Long> envGroups) { + boolean res = true; + if (!mandatoryVos.isEmpty()) { + res = !Collections.disjoint(foundVoIds, mandatoryVos); + } + if (!mandatoryGroups.isEmpty()) { + res = res && !Collections.disjoint(foundGroupIds, mandatoryGroups); + } + if (!envVos.isEmpty()) { + res = res && !Collections.disjoint(foundVoIds, envVos); + } + if (!envGroups.isEmpty()) { + res = res && !Collections.disjoint(foundGroupIds, envGroups); + } + + return res; + } + + public static boolean decideAccess(Set<Long> foundVoIds, Set<Long> foundGroupIds, Set<Long> vos, Set<Long> groups) { + boolean res = true; + if (!vos.isEmpty()) { + res = !Collections.disjoint(foundVoIds, vos); + } + if (!groups.isEmpty()) { + res = res && !Collections.disjoint(foundGroupIds, groups); + } + + return res; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapterMethods.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapterMethods.java new file mode 100644 index 000000000..6ff6560b0 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapterMethods.java @@ -0,0 +1,343 @@ +package cz.muni.ics.oidc.server.adapters; + +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.Group; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.models.Resource; +import cz.muni.ics.oidc.models.Vo; +import cz.muni.ics.oidc.server.PerunPrincipal; +import cz.muni.ics.oidc.server.connectors.Affiliation; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Interface for getting data from Perun interfaces. + * Used for fetching necessary data about users, services etc. + * + * @author Martin Kuba makub@ics.muni.czc + * @author Dominik František Bučík bucik@ics.muni.cz + * @author Peter Jancus jancus@ics.muni.cz + */ +public interface PerunAdapterMethods { + + /** + * Fetch user based on his principal (extLogin and extSource) from Perun + * + * @param perunPrincipal principal of user + * @return PerunUser with id of found user + */ + PerunUser getPreauthenticatedUserId(PerunPrincipal perunPrincipal); + + /** + * Fetch user attribute values + * + * @param user User for whom the attribute values are being fetch + * @param attrsToFetch List of Strings representing attribute values to fetch + * @return Map of attrName:PerunAttributeValue (filled or empty) + */ + Map<String, PerunAttributeValue> getUserAttributeValues(PerunUser user, Collection<String> attrsToFetch); + + /** + * Fetch user attribute values + * + * @param userId Id of the user for whom the attribute values are being fetch + * @param attrsToFetch List of Strings representing attribute values to fetch + * @return Map of attrName:PerunAttributeValue (filled or empty) + */ + Map<String, PerunAttributeValue> getUserAttributeValues(Long userId, Collection<String> attrsToFetch); + + /** + * Fetch user attribute value + * + * @param user User for whom the attribute value is being fetch + * @param attrToFetch String representing attribute value to fetch + * @return PerunAttributeValue or null if not found + */ + PerunAttributeValue getUserAttributeValue(PerunUser user, String attrToFetch); + + /** + * Fetch user attribute value + * + * @param userId Id of user for whom the attribute value is being fetch + * @param attrToFetch String representing attribute value to fetch + * @return PerunAttributeValue or null if not found + */ + PerunAttributeValue getUserAttributeValue(Long userId, String attrToFetch); + + /** + * Fetch facility registered in Perun associated with the given OIDC client_id value. + * + * @param clientId value for the OIDCClientID attribute + * @return Found facility or null + */ + Facility getFacilityByClientId(String clientId); + + /** + * Decide if facility has requested to check membership of user in associated groups before access + * + * @param facility Facility object + * @return TRUE if check should be done, FALSE otherwise + */ + boolean isMembershipCheckEnabledOnFacility(Facility facility); + + /** + * Perform check if user can access service based on his/her membership + * in groups assigned to facility resources + * + * @param facility Facility object + * @param userId ID of user + * @return TRUE if user can access, FALSE otherwise + */ + boolean canUserAccessBasedOnMembership(Facility facility, Long userId); + + /** + * Fetch facility attribute values + * + * @param facility Facility for which the attribute values are being fetch + * @param attrsToFetch List of Strings representing attribute values to fetch + * @return Map of attrName:PerunAttributeValue (filled or empty) + */ + Map<String, PerunAttributeValue> getFacilityAttributeValues(Facility facility, Collection<String> attrsToFetch); + + /** + * Fetch facility attribute values + * + * @param facilityId Id of facility for which the attribute values are being fetch + * @param attrsToFetch List of Strings representing attribute values to fetch + * @return Map of attrName:PerunAttributeValue (filled or empty) + */ + Map<String, PerunAttributeValue> getFacilityAttributeValues(Long facilityId, Collection<String> attrsToFetch); + + /** + * Fetch facility attribute value + * + * @param facility Facility for which the attribute value is being fetch + * @param attrToFetch String representing attribute value to fetch + * @return PerunAttributeValue or null if not found + */ + PerunAttributeValue getFacilityAttributeValue(Facility facility, String attrToFetch); + + /** + * Fetch facility attribute value + * + * @param facilityId Id of facility for which the attribute value is being fetch + * @param attrToFetch String representing attribute value to fetch + * @return PerunAttributeValue or null if not found + */ + PerunAttributeValue getFacilityAttributeValue(Long facilityId, String attrToFetch); + + /** + * Check if user is member of the group + * @param userId ID of user + * @param groupId ID of group + * @return TRUE if the user is member of the group, FALSE otherwise + */ + boolean isUserInGroup(Long userId, Long groupId); + + /** + * For the given user, get all string values of the groupAffiliation attribute of groups of the user + * + * @param userId id of user + * @param groupAffiliationsAttr name of attribute containing group affiliations + * @return List of values of the affiliation attribute (filled or empty) + */ + List<Affiliation> getGroupAffiliations(Long userId, String groupAffiliationsAttr); + + /** + * For the given facility, get all allowed groups + * + * @param facility facility + * @return List of unique names of the groups (filled or empty) + */ + List<String> getGroupsAssignedToResourcesWithUniqueNames(Facility facility); + + /** + * Get groups where user is active (also in VO in which group exists) and are assigned to the resources of facility. + * Fill the uniqueGroupName for groups as well. + * @param facilityId Id of Facility + * @param userId Id of User + * @return Set of groups (filled or empty) + */ + Set<Group> getGroupsWhereUserIsActiveWithUniqueNames(Long facilityId, Long userId); + + /** + * Fetch VO attribute values + * + * @param vo VO for which the attribute values are being fetch + * @param attrsToFetch List of Strings representing attribute values to fetch + * @return Map of attrName:PerunAttributeValue (filled or empty) + */ + Map<String, PerunAttributeValue> getVoAttributeValues(Vo vo, Collection<String> attrsToFetch); + + /** + * Fetch VO attribute values + * + * @param voId Id of VO for which the attribute values are being fetch + * @param attrsToFetch List of Strings representing attribute values to fetch + * @return Map of attrName:PerunAttributeValue (filled or empty) + */ + Map<String, PerunAttributeValue> getVoAttributeValues(Long voId, Collection<String> attrsToFetch); + + /** + * Fetch VO attribute value + * + * @param vo Vo for which the attribute value is being fetch + * @param attrToFetch String representing attribute value to fetch + * @return PerunAttributeValue or null if not found + */ + PerunAttributeValue getVoAttributeValue(Vo vo, String attrToFetch); + + /** + * Fetch VO attribute value + * + * @param voId Id of vo for which the attribute value is being fetch + * @param attrToFetch String representing attribute value to fetch + * @return PerunAttributeValue or null if not found + */ + PerunAttributeValue getVoAttributeValue(Long voId, String attrToFetch); + + /** + * Get vo with the given short name + * + * @param shortName short name of VO + * @return Found VO or null + */ + Vo getVoByShortName(String shortName); + + /** + * Fetch group attribute values + * + * @param group Group for which the attribute values are being fetch + * @param attrsToFetch List of Strings representing attribute values to fetch + * @return Map of attrName:PerunAttributeValue (filled or empty) + */ + Map<String, PerunAttributeValue> getGroupAttributeValues(Group group, Collection<String> attrsToFetch); + + /** + * Fetch group attribute values + * + * @param groupId Id of group for which the attribute values are being fetch + * @param attrsToFetch List of Strings representing attribute values to fetch + * @return Map of attrName:PerunAttributeValue (filled or empty) + */ + Map<String, PerunAttributeValue> getGroupAttributeValues(Long groupId, Collection<String> attrsToFetch); + + /** + * Fetch group attribute value + * + * @param group Group for which the attribute value is being fetch + * @param attrToFetch String representing attribute value to fetch + * @return PerunAttributeValue or null if not found + */ + PerunAttributeValue getGroupAttributeValue(Group group, String attrToFetch); + + /** + * Fetch group attribute value + * + * @param groupId Id of group for which the attribute value is being fetch + * @param attrToFetch String representing attribute value to fetch + * @return PerunAttributeValue or null if not found + */ + PerunAttributeValue getGroupAttributeValue(Long groupId, String attrToFetch); + + /** + * Gets the capabilities + * @param facility Facility representing client + * @param groupNames Names of groups the user is member of. + * @param facilityCapabilitiesAttrName String name of attribute containing facility capabilities. Pass null for ignore. + * @param resourceCapabilitiesAttrName String name of attribute containing resource capabilities. Pass null for ignore. + * @return set of capabilities assigned on resources + */ + Set<String> getCapabilities(Facility facility, Set<String> groupNames, String facilityCapabilitiesAttrName, + String resourceCapabilitiesAttrName); + + /** + * Gets the capabilities + * @param facility Facility representing client + * @param idToGnameMap Map of ID to name of the groups user is member of. + * @param facilityCapabilitiesAttrName String name of attribute containing facility capabilities. Pass null for ignore. + * @param resourceCapabilitiesAttrName String name of attribute containing resource capabilities. Pass null for ignore. + * @return set of capabilities assigned on resources + */ + Set<String> getCapabilities(Facility facility, Map<Long, String> idToGnameMap, String facilityCapabilitiesAttrName, + String resourceCapabilitiesAttrName); + + /** + * Fetch resource attribute values + * + * @param resource Resource for which the attribute values are being fetch + * @param attrsToFetch List of Strings representing attribute values to fetch + * @return Map of attrName:PerunAttributeValue (filled or empty) + */ + Map<String, PerunAttributeValue> getResourceAttributeValues(Resource resource, Collection<String> attrsToFetch); + + /** + * Fetch resource attribute values + * + * @param resourceId Id of resource for which the attribute values are being fetch + * @param attrsToFetch List of Strings representing attribute values to fetch + * @return Map of attrName:PerunAttributeValue (filled or empty) + */ + Map<String, PerunAttributeValue> getResourceAttributeValues(Long resourceId, Collection<String> attrsToFetch); + + /** + * Fetch resource attribute value + * + * @param resource Resource for which the attribute value is being fetch + * @param attrToFetch String representing attribute value to fetch + * @return PerunAttributeValue or null if not found + */ + PerunAttributeValue getResourceAttributeValue(Resource resource, String attrToFetch); + + /** + * Fetch resource attribute value + * + * @param resourceId Id of resource for which the attribute value is being fetch + * @param attrToFetch String representing attribute value to fetch + * @return PerunAttributeValue or null if not found + */ + PerunAttributeValue getResourceAttributeValue(Long resourceId, String attrToFetch); + + /** + * Fetch group IDs where user is member based on userID and voID + * @param userId id of user + * @param voId id of vo + * @return List of groups IDs (filled or empty) + */ + Set<Long> getUserGroupsIds(Long userId, Long voId); + + /** + * Check if user is valid member of given VOs (identified by IDs) + * @param userId ID of user in Perun + * @param mandatoryVos Set of IDs identifying the VOs + * @param mandatoryGroups Set of IDs identifying the Groups + * @param envVos Set of IDs identifying the VOs + * @param envGroups Set of IDs identifying the Groups + * @return returns TRUE if: + * User is member of at least one specified mandatory VO, and + * User is member of at least one specified mandatory GROUP, and + * User is member of at least one specified env VO, and + * User is member of at least one specified env GROUP. + * Returns FALSE otherwise. + */ + boolean isValidMemberInGroupsAndVos(Long userId, Set<Long> mandatoryVos, Set<Long> mandatoryGroups, + Set<Long> envVos, Set<Long> envGroups); + + /** + * Check if user is valid member of given VOs (identified by IDs) + * @param userId ID of user in Perun + * @param vos Set of IDs identifying the VOs + * @param groups Set of IDs identifying the Groups + * @return returns TRUE if: + * User is member of at least one specified mandatory VO, and + * User is member of at least one specified mandatory GROUP, and + * Returns FALSE otherwise. + */ + boolean isValidMemberInGroupsAndVos(Long userId, Set<Long> vos, Set<Long> groups); + + boolean isUserInVo(Long userId, String voShortName); + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapterMethodsLdap.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapterMethodsLdap.java new file mode 100644 index 000000000..6a4834128 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapterMethodsLdap.java @@ -0,0 +1,9 @@ +package cz.muni.ics.oidc.server.adapters; + +/** + * Interface with specific methods that only LDAP interface can execute + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public interface PerunAdapterMethodsLdap { +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapterMethodsRpc.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapterMethodsRpc.java new file mode 100644 index 000000000..46926a3ad --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/PerunAdapterMethodsRpc.java @@ -0,0 +1,231 @@ +package cz.muni.ics.oidc.server.adapters; + +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.Group; +import cz.muni.ics.oidc.models.PerunAttribute; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.models.Resource; +import cz.muni.ics.oidc.models.Vo; +import cz.muni.ics.oidc.server.connectors.Affiliation; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Interface with specific methods that only rpc interface can execute + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public interface PerunAdapterMethodsRpc { + + /** + * Get list of groups where user can register to gain access to the service + * + * @param facility facility the user tries to access + * @param userId id of user + * @return List of groups where user can register or empty list + */ + Map<Vo, List<Group>> getGroupsForRegistration(Facility facility, Long userId, List<String> voShortNames); + + /** + * Decide if there is a group where user can register + * + * @param facility facility being accessed + * @return true if at least one group with registration form exists + */ + boolean groupWhereCanRegisterExists(Facility facility); + + /** + * Sets the attribute of the user. + * @param userId id of user + * @param attribute attribute + */ + boolean setUserAttribute(Long userId, PerunAttribute attribute); + + /** + * For the given user, gets all string values of the affiliation attribute of all UserExtSources of type ExtSourceIdp + * @param userId id of user + * @return list of values of attribute affiliation + */ + List<Affiliation> getUserExtSourcesAffiliations(Long userId); + + /** + * Gets the map of entityless attributes. + * @param attributeName full name of attribute + * @return map of attributes + */ + Map<String, PerunAttribute> getEntitylessAttributes(String attributeName); + + /** + * Fetch facility attributes + * @param facility Facility for which the attribute values are being fetched. + * @param attrsToFetch Collection of String representing attribute values to fetch + * @return Map of attrName:PerunAttribute (filled or empty) + */ + Map<String, PerunAttribute> getFacilityAttributes(Facility facility, Collection<String> attrsToFetch); + + /** + * Fetch facility attributes + * @param facilityId Id of facility for which the attribute values are being fetched. + * @param attrsToFetch Collection of String representing attribute values to fetch + * @return Map of attrName:PerunAttribute (filled or empty) + */ + Map<String, PerunAttribute> getFacilityAttributes(Long facilityId, Collection<String> attrsToFetch); + + /** + * Fetch group attributes + * @param group Group for which the attribute values are being fetched. + * @param attrsToFetch Collection of String representing attribute values to fetch + * @return Map of attrName:PerunAttribute (filled or empty) + */ + Map<String, PerunAttribute> getGroupAttributes(Group group, Collection<String> attrsToFetch); + + /** + * Fetch facility attribute value + * + * @param facility Facility for which the attribute is being fetched + * @param attrToFetch String representing attribute to fetch + * @return PerunAttribute + */ + PerunAttribute getFacilityAttribute(Facility facility, String attrToFetch); + + /** + * Fetch facility attribute value + * + * @param facilityId Id of facility for which the attribute is being fetched + * @param attrToFetch String representing attribute to fetch + * @return PerunAttribute + */ + PerunAttribute getFacilityAttribute(Long facilityId, String attrToFetch); + + /** + * Fetch group attributes + * @param groupId Id of group for which the attribute values are being fetched. + * @param attrsToFetch Collection of String representing attribute values to fetch + * @return Map of attrName:PerunAttribute (filled or empty) + */ + Map<String, PerunAttribute> getGroupAttributes(Long groupId, Collection<String> attrsToFetch); + + /** + * Fetch group attribute value + * + * @param group Group for which the attribute is being fetched + * @param attrToFetch String representing attribute to fetch + * @return PerunAttribute + */ + PerunAttribute getGroupAttribute(Group group, String attrToFetch); + + /** + * Fetch group attribute value + * + * @param groupId Id of group for which the attribute is being fetched + * @param attrToFetch String representing attribute to fetch + * @return PerunAttribute + */ + PerunAttribute getGroupAttribute(Long groupId, String attrToFetch); + + /** + * Fetch user attributes + * @param user User for whom the attribute values are being fetched. + * @param attrsToFetch Collection of String representing attribute values to fetch + * @return Map of attrName:PerunAttribute (filled or empty) + */ + Map<String, PerunAttribute> getUserAttributes(PerunUser user, Collection<String> attrsToFetch); + + /** + * Fetch user attributes + * @param userId Id of user for whom the attribute values are being fetched. + * @param attrsToFetch Collection of String representing attribute values to fetch + * @return Map of attrName:PerunAttribute (filled or empty) + */ + Map<String, PerunAttribute> getUserAttributes(Long userId, Collection<String> attrsToFetch); + + /** + * Fetch user attribute value + * + * @param user User for whom the attribute is being fetched + * @param attrToFetch String representing attribute to fetch + * @return PerunAttribute + */ + PerunAttribute getUserAttribute(PerunUser user, String attrToFetch); + + /** + * Fetch user attribute value + * + * @param userId Id of user for whom the attribute is being fetched + * @param attrToFetch String representing attribute to fetch + * @return PerunAttribute + */ + PerunAttribute getUserAttribute(Long userId, String attrToFetch); + + /** + * Fetch vo attributes + * @param vo VO for which the attribute values are being fetched. + * @param attrsToFetch Collection of String representing attribute values to fetch + * @return Map of attrName:PerunAttribute (filled or empty) + */ + Map<String, PerunAttribute> getVoAttributes(Vo vo, Collection<String> attrsToFetch); + + /** + * Fetch vo attributes + * @param voId Id of VO for which the attribute values are being fetched. + * @param attrsToFetch Collection of String representing attribute values to fetch + * @return Map of attrName:PerunAttribute (filled or empty) + */ + Map<String, PerunAttribute> getVoAttributes(Long voId, Collection<String> attrsToFetch); + + /** + * Fetch VO attribute + * + * @param vo Vo for which the attribute is being fetched + * @param attrToFetch String representing attribute to fetch + * @return PerunAttribute + */ + PerunAttribute getVoAttribute(Vo vo, String attrToFetch); + + /** + * Fetch VO attribute + * + * @param voId Id of vo for which the attribute is being fetched + * @param attrToFetch String representing attribute to fetch + * @return PerunAttribute + */ + PerunAttribute getVoAttribute(Long voId, String attrToFetch); + + /** + * Fetch resource attributes + * @param resource VO for which the attribute values are being fetched. + * @param attrsToFetch Collection of String representing attribute values to fetch + * @return Map of attrName:PerunAttribute (filled or empty) + */ + Map<String, PerunAttribute> getResourceAttributes(Resource resource, Collection<String> attrsToFetch); + + /** + * Fetch resource attributes + * @param resourceId Id of VO for which the attribute values are being fetched. + * @param attrsToFetch Collection of String representing attribute values to fetch + * @return Map of attrName:PerunAttribute (filled or empty) + */ + Map<String, PerunAttribute> getResourceAttributes(Long resourceId, Collection<String> attrsToFetch); + + /** + * Fetch VO attribute + * + * @param resource Resource for which the attribute is being fetched + * @param attrToFetch String representing attribute to fetch + * @return PerunAttribute + */ + PerunAttribute getResourceAttribute(Resource resource, String attrToFetch); + + /** + * Fetch VO attribute + * + * @param resourceId Id of resource for which the attribute is being fetched + * @param attrToFetch String representing attribute to fetch + * @return PerunAttribute + */ + PerunAttribute getResourceAttribute(Long resourceId, String attrToFetch); + + boolean hasApplicationForm(String voShortName); + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterImpl.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterImpl.java new file mode 100644 index 000000000..93492df00 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterImpl.java @@ -0,0 +1,404 @@ +package cz.muni.ics.oidc.server.adapters.impl; + +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.Group; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.models.Resource; +import cz.muni.ics.oidc.models.Vo; +import cz.muni.ics.oidc.server.PerunPrincipal; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.connectors.Affiliation; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Basic adapter. This one should be used across the application to call the methods that are common + * among all adapters. Otherwise use secific adapter. + * + * @author Dominik František Bučík <bucik@ics.muni.cz> + */ +public class PerunAdapterImpl extends PerunAdapter { + + @Override + public PerunUser getPreauthenticatedUserId(PerunPrincipal perunPrincipal) { + try { + return this.getAdapterPrimary().getPreauthenticatedUserId(perunPrincipal); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getPreauthenticatedUserId(perunPrincipal); + } else { + throw e; + } + } + } + + @Override + public Facility getFacilityByClientId(String clientId) { + try { + return this.getAdapterPrimary().getFacilityByClientId(clientId); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getFacilityByClientId(clientId); + } else { + throw e; + } + } + } + + @Override + public boolean isMembershipCheckEnabledOnFacility(Facility facility) { + try { + return this.getAdapterPrimary().isMembershipCheckEnabledOnFacility(facility); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().isMembershipCheckEnabledOnFacility(facility); + } else { + throw e; + } + } + } + + @Override + public boolean canUserAccessBasedOnMembership(Facility facility, Long userId) { + try { + return this.getAdapterPrimary().canUserAccessBasedOnMembership(facility, userId); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().canUserAccessBasedOnMembership(facility, userId); + } else { + throw e; + } + } + } + + + @Override + public boolean isUserInGroup(Long userId, Long groupId) { + try { + return this.getAdapterPrimary().isUserInGroup(userId, groupId); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().isUserInGroup(userId, groupId); + } else { + throw e; + } + } + } + + @Override + public List<Affiliation> getGroupAffiliations(Long userId, String groupAffiliationsAttr) { + try { + return this.getAdapterPrimary().getGroupAffiliations(userId, groupAffiliationsAttr); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getGroupAffiliations(userId, groupAffiliationsAttr); + } else { + throw e; + } + } + } + + @Override + public List<String> getGroupsAssignedToResourcesWithUniqueNames(Facility facility) { + try { + return this.getAdapterPrimary().getGroupsAssignedToResourcesWithUniqueNames(facility); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getGroupsAssignedToResourcesWithUniqueNames(facility); + } else { + throw e; + } + } + } + + @Override + public Vo getVoByShortName(String shortName) { + try { + return this.getAdapterPrimary().getVoByShortName(shortName); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getVoByShortName(shortName); + } else { + throw e; + } + } + } + + @Override + public Map<String, PerunAttributeValue> getUserAttributeValues(PerunUser user, Collection<String> attrsToFetch) { + return this.getUserAttributeValues(user.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getUserAttributeValues(Long userId, Collection<String> attrsToFetch) { + try { + return this.getAdapterPrimary().getUserAttributeValues(userId, attrsToFetch); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getUserAttributeValues(userId, attrsToFetch); + } else { + throw e; + } + } + } + + @Override + public PerunAttributeValue getUserAttributeValue(PerunUser user, String attrToFetch) { + return this.getUserAttributeValue(user.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getUserAttributeValue(Long userId, String attrToFetch) { + try { + return this.getAdapterPrimary().getUserAttributeValue(userId, attrToFetch); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getUserAttributeValue(userId, attrToFetch); + } else { + throw e; + } + } + } + + @Override + public Map<String, PerunAttributeValue> getFacilityAttributeValues(Facility facility, Collection<String> attrsToFetch) { + return this.getFacilityAttributeValues(facility.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getFacilityAttributeValues(Long facilityId, Collection<String> attrsToFetch) { + try { + return this.getAdapterPrimary().getFacilityAttributeValues(facilityId, attrsToFetch); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getFacilityAttributeValues(facilityId, attrsToFetch); + } else { + throw e; + } + } + } + + @Override + public PerunAttributeValue getFacilityAttributeValue(Facility facility, String attrToFetch) { + return this.getFacilityAttributeValue(facility.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getFacilityAttributeValue(Long facilityId, String attrToFetch) { + try { + return this.getAdapterPrimary().getFacilityAttributeValue(facilityId, attrToFetch); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getFacilityAttributeValue(facilityId, attrToFetch); + } else { + throw e; + } + } + } + + @Override + public Map<String, PerunAttributeValue> getVoAttributeValues(Vo vo, Collection<String> attrsToFetch) { + return this.getVoAttributeValues(vo.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getVoAttributeValues(Long voId, Collection<String> attrsToFetch) { + try { + return this.getAdapterPrimary().getVoAttributeValues(voId, attrsToFetch); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getVoAttributeValues(voId, attrsToFetch); + } else { + throw e; + } + } + } + + @Override + public PerunAttributeValue getVoAttributeValue(Vo vo, String attrToFetch) { + return this.getVoAttributeValue(vo.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getVoAttributeValue(Long voId, String attrToFetch) { + try { + return this.getAdapterPrimary().getVoAttributeValue(voId, attrToFetch); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getVoAttributeValue(voId, attrToFetch); + } else { + throw e; + } + } + } + + @Override + public Map<String, PerunAttributeValue> getGroupAttributeValues(Group group, Collection<String> attrsToFetch) { + return this.getGroupAttributeValues(group.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getGroupAttributeValues(Long groupId, Collection<String> attrsToFetch) { + try { + return this.getAdapterPrimary().getGroupAttributeValues(groupId, attrsToFetch); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getGroupAttributeValues(groupId, attrsToFetch); + } else { + throw e; + } + } + } + + @Override + public PerunAttributeValue getGroupAttributeValue(Group group, String attrToFetch) { + return this.getGroupAttributeValue(group.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getGroupAttributeValue(Long groupId, String attrToFetch) { + try { + return this.getAdapterPrimary().getGroupAttributeValue(groupId, attrToFetch); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getGroupAttributeValue(groupId, attrToFetch); + } else { + throw e; + } + } + } + + @Override + public Map<String, PerunAttributeValue> getResourceAttributeValues(Resource resource, Collection<String> attrsToFetch) { + return this.getResourceAttributeValues(resource.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getResourceAttributeValues(Long resourceId, Collection<String> attrsToFetch) { + try { + return this.getAdapterPrimary().getResourceAttributeValues(resourceId, attrsToFetch); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getResourceAttributeValues(resourceId, attrsToFetch); + } else { + throw e; + } + } + } + + @Override + public PerunAttributeValue getResourceAttributeValue(Resource resource, String attrToFetch) { + return this.getResourceAttributeValue(resource.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getResourceAttributeValue(Long resourceId, String attrToFetch) { + try { + return this.getAdapterPrimary().getResourceAttributeValue(resourceId, attrToFetch); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getResourceAttributeValue(resourceId, attrToFetch); + } else { + throw e; + } + } + } + + @Override + public Set<String> getCapabilities(Facility facility, Set<String> groupNames, String facilityCapabilitiesAttrName, String resourceCapabilitiesAttrName) { + try { + return this.getAdapterPrimary().getCapabilities(facility, groupNames, facilityCapabilitiesAttrName, resourceCapabilitiesAttrName); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getCapabilities(facility, groupNames, facilityCapabilitiesAttrName, resourceCapabilitiesAttrName); + } else { + throw e; + } + } + } + + @Override + public Set<String> getCapabilities(Facility facility, Map<Long, String> idToGnameMap, String facilityCapabilitiesAttrName, String resourceCapabilitiesAttrName) { + try { + return this.getAdapterPrimary().getCapabilities(facility, idToGnameMap, facilityCapabilitiesAttrName, resourceCapabilitiesAttrName); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getCapabilities(facility, idToGnameMap, facilityCapabilitiesAttrName, resourceCapabilitiesAttrName); + } else { + throw e; + } + } + } + + @Override + public Set<Group> getGroupsWhereUserIsActiveWithUniqueNames(Long facilityId, Long userId) { + try { + return this.getAdapterPrimary().getGroupsWhereUserIsActiveWithUniqueNames(facilityId, userId); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getGroupsWhereUserIsActiveWithUniqueNames(facilityId, userId); + } else { + throw e; + } + } + } + + @Override + public Set<Long> getUserGroupsIds(Long userId, Long voId) { + try { + return this.getAdapterPrimary().getUserGroupsIds(userId, voId); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().getUserGroupsIds(userId, voId); + } else { + throw e; + } + } + } + + @Override + public boolean isValidMemberInGroupsAndVos(Long userId, Set<Long> mandatoryVos, Set<Long> mandatoryGroups, + Set<Long> envVos, Set<Long> envGroups) { + try { + return this.getAdapterPrimary().isValidMemberInGroupsAndVos(userId, mandatoryVos, mandatoryGroups, + envVos, envGroups); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().isValidMemberInGroupsAndVos(userId, mandatoryVos, mandatoryGroups, + envVos, envGroups); + } else { + throw e; + } + } + } + + @Override + public boolean isValidMemberInGroupsAndVos(Long userId, Set<Long> vos, Set<Long> groups) { + try { + return this.getAdapterPrimary().isValidMemberInGroupsAndVos(userId, vos, groups); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().isValidMemberInGroupsAndVos(userId, vos, groups); + } else { + throw e; + } + } + } + + @Override + public boolean isUserInVo(Long userId, String voShortName) { + try { + return this.getAdapterPrimary().isUserInVo(userId, voShortName); + } catch (UnsupportedOperationException e) { + if (this.isCallFallback()) { + return this.getAdapterFallback().isUserInVo(userId, voShortName); + } else { + throw e; + } + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterLdap.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterLdap.java new file mode 100644 index 000000000..752cdf4fa --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterLdap.java @@ -0,0 +1,867 @@ +package cz.muni.ics.oidc.server.adapters.impl; + +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.ASSIGNED_GROUP_ID; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.CN; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.DESCRIPTION; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.EDU_PERSON_PRINCIPAL_NAMES; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.GIVEN_NAME; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.MEMBER_OF; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.O; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.OBJECT_CLASS; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.OU_PEOPLE; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_FACILITY; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_FACILITY_DN; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_FACILITY_ID; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_GROUP; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_GROUP_ID; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_PARENT_GROUP_ID; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_RESOURCE; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_RESOURCE_ID; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_UNIQUE_GROUP_NAME; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_USER; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_USER_ID; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_VO; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.PERUN_VO_ID; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.SN; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.UNIQUE_MEMBER; +import static cz.muni.ics.oidc.server.adapters.impl.PerunAdapterLdapConstants.UUID; +import static org.apache.directory.ldap.client.api.search.FilterBuilder.and; +import static org.apache.directory.ldap.client.api.search.FilterBuilder.equal; +import static org.apache.directory.ldap.client.api.search.FilterBuilder.or; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import cz.muni.ics.oidc.exceptions.InconvertibleValueException; +import cz.muni.ics.oidc.models.AttributeMapping; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.Group; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.models.Resource; +import cz.muni.ics.oidc.models.Vo; +import cz.muni.ics.oidc.models.enums.PerunAttrValueType; +import cz.muni.ics.oidc.models.enums.PerunEntityType; +import cz.muni.ics.oidc.server.PerunPrincipal; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.adapters.PerunAdapterMethods; +import cz.muni.ics.oidc.server.adapters.PerunAdapterMethodsLdap; +import cz.muni.ics.oidc.server.connectors.Affiliation; +import cz.muni.ics.oidc.server.connectors.PerunConnectorLdap; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import org.apache.directory.api.ldap.model.entry.Attribute; +import org.apache.directory.api.ldap.model.entry.Entry; +import org.apache.directory.api.ldap.model.entry.Value; +import org.apache.directory.api.ldap.model.message.SearchScope; +import org.apache.directory.ldap.client.api.search.FilterBuilder; +import org.apache.directory.ldap.client.template.EntryMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +/** + * Connects to Perun using LDAP. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + * @author Martin Kuba makub@ics.muni.cz + */ +public class PerunAdapterLdap extends PerunAdapterWithMappingServices implements PerunAdapterMethods, PerunAdapterMethodsLdap { + + private final static Logger log = LoggerFactory.getLogger(PerunAdapterLdap.class); + + private PerunConnectorLdap connectorLdap; + private String oidcClientIdAttr; + private String oidcCheckMembershipAttr; + private final JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance; + + public void setConnectorLdap(PerunConnectorLdap connectorLdap) { + this.connectorLdap = connectorLdap; + } + + public void setOidcClientIdAttr(String oidcClientIdAttr) { + this.oidcClientIdAttr = oidcClientIdAttr; + } + + public void setOidcCheckMembershipAttr(String oidcCheckMembershipAttr) { + this.oidcCheckMembershipAttr = oidcCheckMembershipAttr; + } + + /** + * Fetch user based on his principal (extLogin and extSource) from Perun + * + * @param perunPrincipal principal of user + * @return PerunUser with id of found user + */ + @Override + public PerunUser getPreauthenticatedUserId(PerunPrincipal perunPrincipal) { + FilterBuilder filter = and( + equal(OBJECT_CLASS, PERUN_USER), equal(EDU_PERSON_PRINCIPAL_NAMES, perunPrincipal.getExtLogin()) + ); + SearchScope scope = SearchScope.ONELEVEL; + String[] attributes = new String[]{PERUN_USER_ID, GIVEN_NAME, SN}; + EntryMapper<PerunUser> mapper = e -> { + if (!checkHasAttributes(e, new String[] { PERUN_USER_ID, SN })) { + return null; + } + + long id = Long.parseLong(e.get(PERUN_USER_ID).getString()); + String firstName = (e.get(GIVEN_NAME) != null) ? e.get(GIVEN_NAME).getString() : null; + String lastName = e.get(SN).getString(); + return new PerunUser(id, firstName, lastName); + }; + + return connectorLdap.searchFirst(OU_PEOPLE, filter, scope, attributes, mapper); + } + + @Override + public Facility getFacilityByClientId(String clientId) { + if (!StringUtils.hasText(clientId)) { + return null; + } + SearchScope scope = SearchScope.ONELEVEL; + String[] attributes = new String[]{PERUN_FACILITY_ID, DESCRIPTION, CN}; + EntryMapper<Facility> mapper = e -> { + if (!checkHasAttributes(e, attributes)) { + return null; + } + + long id = Long.parseLong(e.get(PERUN_FACILITY_ID).getString()); + String name = e.get(CN).getString(); + String description = e.get(DESCRIPTION).getString(); + + return new Facility(id, name, description); + }; + + AttributeMapping mapping = this.getFacilityAttributesMappingService().getMappingByIdentifier(oidcClientIdAttr); + + FilterBuilder filter = and(equal(OBJECT_CLASS, PERUN_FACILITY), equal(mapping.getLdapName(), clientId)); + return connectorLdap.searchFirst(null, filter, scope, attributes, mapper); + } + + @Override + public boolean isMembershipCheckEnabledOnFacility(Facility facility) { + boolean res = false; + + PerunAttributeValue attrVal = getFacilityAttributeValue(facility, oidcCheckMembershipAttr); + if (attrVal != null && !attrVal.isNullValue()) { + res = attrVal.valueAsBoolean(); + } + + return res; + } + + @Override + public boolean canUserAccessBasedOnMembership(Facility facility, Long userId) { + Set<Long> groupsWithAccessIds = getGroupIdsWithAccessToFacility(facility.getId()); + if (groupsWithAccessIds == null || groupsWithAccessIds.isEmpty()) { + return false; + } + + Set<Long> userGroupIds = getGroupIdsWhereUserIsMember(userId, null); + if (userGroupIds == null || userGroupIds.isEmpty()) { + return false; + } + + return !Collections.disjoint(userGroupIds, groupsWithAccessIds); + } + + @Override + public boolean isUserInGroup(Long userId, Long groupId) { + String uniqueMemberValue = PERUN_USER_ID + '=' + userId + ',' + OU_PEOPLE + ',' + connectorLdap.getBaseDN(); + FilterBuilder filter = and( + equal(OBJECT_CLASS, PERUN_GROUP), + equal(PERUN_GROUP_ID, String.valueOf(groupId)), + equal(UNIQUE_MEMBER, uniqueMemberValue) + ); + + EntryMapper<Long> mapper = e -> Long.parseLong(e.get(PERUN_GROUP_ID).getString()); + + String[] attributes = new String[] { PERUN_GROUP_ID }; + + List<Long> ids = connectorLdap.search(null, filter, SearchScope.SUBTREE, attributes, mapper); + return ids.stream().filter(groupId::equals).count() == 1L; + } + + @Override + public List<Affiliation> getGroupAffiliations(Long userId, String groupAffiliationsAttr) { + Set<Long> userGroupIds = getGroupIdsWhereUserIsMember(userId, null); + if (userGroupIds == null || userGroupIds.isEmpty()) { + return new ArrayList<>(); + } + + FilterBuilder[] groupIdFilters = new FilterBuilder[userGroupIds.size()]; + int i = 0; + for (Long id: userGroupIds) { + groupIdFilters[i++] = equal(PERUN_GROUP_ID, String.valueOf(id)); + } + + AttributeMapping affiliationsMapping = getGroupAttributesMappingService().getMappingByIdentifier(groupAffiliationsAttr); + + FilterBuilder filterBuilder = and(equal(OBJECT_CLASS, PERUN_GROUP), or(groupIdFilters)); + String[] attributes = new String[] { affiliationsMapping.getLdapName() }; + EntryMapper<Set<Affiliation>> mapper = e -> { + Set<Affiliation> affiliations = new HashSet<>(); + if (!checkHasAttributes(e, attributes)) { + return affiliations; + } + + Attribute a = e.get(affiliationsMapping.getLdapName()); + long linuxTime = System.currentTimeMillis() / 1000L; + a.iterator().forEachRemaining(v -> affiliations.add(new Affiliation(null, v.getString(), linuxTime))); + + return affiliations; + }; + + List<Set<Affiliation>> affiliationSets = connectorLdap.search(null, filterBuilder, SearchScope.SUBTREE, attributes, mapper); + + return affiliationSets.stream().flatMap(Set::stream).distinct().collect(Collectors.toList()); + } + + @Override + public List<String> getGroupsAssignedToResourcesWithUniqueNames(Facility facility) { + List<String> res = new ArrayList<>(); + + Set<Long> groupIds = getGroupIdsWithAccessToFacility(facility.getId()); + if (groupIds == null || groupIds.isEmpty()) { + return res; + } + + FilterBuilder[] partialFilters = new FilterBuilder[groupIds.size()]; + int i = 0; + for (Long id: groupIds) { + partialFilters[i++] = equal(PERUN_GROUP_ID, String.valueOf(id)); + } + + FilterBuilder filter = and(equal(OBJECT_CLASS, PERUN_GROUP), or(partialFilters)); + String[] attributes = new String[] {PERUN_UNIQUE_GROUP_NAME}; + EntryMapper<String> mapper = e -> { + if (!checkHasAttributes(e, attributes)) { + return null; + } + + return e.get(PERUN_UNIQUE_GROUP_NAME).getString(); + }; + + List<String> uniqueGroupNames = connectorLdap.search(null, filter, SearchScope.SUBTREE, attributes, mapper); + uniqueGroupNames = uniqueGroupNames.stream().filter(Objects::nonNull).collect(Collectors.toList()); + return uniqueGroupNames; + } + + @Override + public Vo getVoByShortName(String shortName) { + FilterBuilder filter = and(equal(OBJECT_CLASS, PERUN_VO), equal(O, shortName)); + String[] attributes = new String[] { PERUN_VO_ID, O, DESCRIPTION }; + EntryMapper<Vo> mapper = e -> { + if (!checkHasAttributes(e, attributes)) { + return null; + } + + Long id = Long.valueOf(e.get(PERUN_VO_ID).getString()); + String shortNameVo = e.get(O).getString(); + String name = e.get(DESCRIPTION).getString(); + + return new Vo(id, name, shortNameVo); + }; + + return connectorLdap.searchFirst(null, filter, SearchScope.ONELEVEL, attributes, mapper); + } + + @Override + public Map<String, PerunAttributeValue> getUserAttributeValues(PerunUser user, Collection<String> attrsToFetch) { + return this.getUserAttributeValues(user.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getUserAttributeValues(Long userId, Collection<String> attrsToFetch) { + String dnPrefix = PERUN_USER_ID + '=' + userId + ',' + OU_PEOPLE; + return getAttributeValues(dnPrefix, attrsToFetch, PerunEntityType.USER); + } + + @Override + public PerunAttributeValue getUserAttributeValue(PerunUser user, String attrToFetch) { + return this.getUserAttributeValue(user.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getUserAttributeValue(Long userId, String attrToFetch) { + Map<String, PerunAttributeValue> map = this.getUserAttributeValues( + userId, Collections.singletonList(attrToFetch)); + return map.getOrDefault(attrToFetch, null); + } + + @Override + public Map<String, PerunAttributeValue> getFacilityAttributeValues(Facility facility, Collection<String> attrsToFetch) { + return this.getFacilityAttributeValues(facility.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getFacilityAttributeValues(Long facilityId, Collection<String> attrsToFetch) { + String dnPrefix = PERUN_FACILITY_ID + '=' + facilityId; + return getAttributeValues(dnPrefix, attrsToFetch, PerunEntityType.FACILITY); + } + + @Override + public PerunAttributeValue getFacilityAttributeValue(Facility facility, String attrToFetch) { + return this.getFacilityAttributeValue(facility.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getFacilityAttributeValue(Long facilityId, String attrToFetch) { + Map<String, PerunAttributeValue> map = this.getFacilityAttributeValues( + facilityId, Collections.singletonList(attrToFetch)); + return map.getOrDefault(attrToFetch, null); + } + + @Override + public Map<String, PerunAttributeValue> getVoAttributeValues(Vo vo, Collection<String> attrsToFetch) { + return this.getVoAttributeValues(vo.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getVoAttributeValues(Long voId, Collection<String> attrsToFetch) { + String dnPrefix = PERUN_VO_ID + '=' + voId; + return getAttributeValues(dnPrefix, attrsToFetch, PerunEntityType.VO); + } + + @Override + public PerunAttributeValue getVoAttributeValue(Vo vo, String attrToFetch) { + return this.getVoAttributeValue(vo.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getVoAttributeValue(Long voId, String attrToFetch) { + Map<String, PerunAttributeValue> map = this.getVoAttributeValues( + voId, Collections.singletonList(attrToFetch)); + return map.getOrDefault(attrToFetch, null); + } + + @Override + public Map<String, PerunAttributeValue> getGroupAttributeValues(Group group, Collection<String> attrsToFetch) { + return this.getGroupAttributeValues(group.getVoId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getGroupAttributeValues(Long groupId, Collection<String> attrsToFetch) { + String dnPrefix = PERUN_GROUP_ID + '=' + groupId; + return getAttributeValues(dnPrefix, attrsToFetch, PerunEntityType.GROUP); + } + + @Override + public PerunAttributeValue getGroupAttributeValue(Group group, String attrToFetch) { + return this.getGroupAttributeValue(group.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getGroupAttributeValue(Long groupId, String attrToFetch) { + Map<String, PerunAttributeValue> map = this.getGroupAttributeValues( + groupId, Collections.singletonList(attrToFetch)); + return map.getOrDefault(attrToFetch, null); + } + + @Override + public Map<String, PerunAttributeValue> getResourceAttributeValues(Resource resource, Collection<String> attrsToFetch) { + return this.getResourceAttributeValues(resource.getVoId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getResourceAttributeValues(Long resourceId, Collection<String> attrsToFetch) { + String dnPrefix = PERUN_RESOURCE_ID + '=' + resourceId; + return getAttributeValues(dnPrefix, attrsToFetch, PerunEntityType.RESOURCE); + } + + @Override + public PerunAttributeValue getResourceAttributeValue(Resource resource, String attrToFetch) { + return this.getResourceAttributeValue(resource.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getResourceAttributeValue(Long resourceId, String attrToFetch) { + Map<String, PerunAttributeValue> map = this.getResourceAttributeValues( + resourceId, Collections.singletonList(attrToFetch)); + return map.getOrDefault(attrToFetch, null); + } + + @Override + public Set<String> getCapabilities(Facility facility, Set<String> groupNames, + String facilityCapabilitiesAttrName, + String resourceCapabilitiesAttrName) + { + if (facility == null) { + return new HashSet<>(); + } else if (groupNames == null || groupNames.isEmpty()) { + return new HashSet<>(); + } + + Set<Long> groupIdsFromGNames = getGroupsByUniqueGroupNames(groupNames).stream() + .map(Group::getId).collect(Collectors.toSet()); + + FilterBuilder[] parts = new FilterBuilder[groupIdsFromGNames.size()]; + int i = 0; + for (Long gid : groupIdsFromGNames) { + parts[i] = equal(ASSIGNED_GROUP_ID, String.valueOf(gid)); + i++; + } + return getCapabilities(facility, facilityCapabilitiesAttrName, resourceCapabilitiesAttrName, parts); + } + + @Override + public Set<String> getCapabilities(Facility facility, Map<Long, String> idToGnameMap, + String facilityCapabilitiesAttrName, String resourceCapabilitiesAttrName) + { + if (facility == null) { + return new HashSet<>(); + } else if (idToGnameMap == null || idToGnameMap.isEmpty()) { + return new HashSet<>(); + } + + FilterBuilder[] parts = new FilterBuilder[idToGnameMap.size()]; + int i = 0; + for (Long gid : idToGnameMap.keySet()) { + parts[i] = equal(ASSIGNED_GROUP_ID, String.valueOf(gid)); + i++; + } + return getCapabilities(facility, facilityCapabilitiesAttrName, resourceCapabilitiesAttrName, parts); + } + + @Override + public Set<Group> getGroupsWhereUserIsActiveWithUniqueNames(Long facilityId, Long userId) { + Set<Long> userGroups = this.getGroupIdsWhereUserIsMember(userId, null); + Set<Long> facilityGroups = this.getGroupIdsWithAccessToFacility(facilityId); + Set<Long> groupIds = userGroups.stream() + .filter(facilityGroups::contains) + .collect(Collectors.toSet()); + log.debug("Intersection of userGroups and facilityGroups: {}", groupIds); + Set<Group> groups = new HashSet<>(); + + if (groupIds.isEmpty()) { + return groups; + } + + List<Group> resGroups = getGroups(groupIds, PERUN_GROUP_ID); + groups = new HashSet<>(resGroups); + + return groups; + } + + @Override + public Set<Long> getUserGroupsIds(Long userId, Long voId) { + return getGroupIdsWhereUserIsMember(userId, voId); + } + + @Override + public boolean isValidMemberInGroupsAndVos(Long userId, Set<Long> mandatoryVos, Set<Long> mandatoryGroups, + Set<Long> envVos, Set<Long> envGroups) { + final Set<Long> foundGroupIds = new HashSet<>(); + final Set<Long> foundVoIds = new HashSet<>(); + String dnPrefix = getDnPrefixForUserId(userId); + String[] attributes = new String[] { MEMBER_OF }; + EntryMapper<Void> mapper = e -> { + if (checkHasAttributes(e, attributes)) { + Attribute a = e.get(MEMBER_OF); + a.iterator().forEachRemaining(id -> { + String fullVal = id.getString(); + String[] parts = fullVal.split(",", 3); + + String groupId = parts[0]; + groupId = groupId.replace(PERUN_GROUP_ID + '=', ""); + foundGroupIds.add(Long.parseLong(groupId)); + String voIdStr = parts[1]; + voIdStr = voIdStr.replace(PERUN_VO_ID + '=', ""); + foundVoIds.add(Long.parseLong(voIdStr)); + }); + } + return null; + }; + connectorLdap.lookup(dnPrefix, attributes, mapper); + + return PerunAdapter.decideAccess(foundVoIds, foundGroupIds, mandatoryVos, mandatoryGroups, envVos, envGroups); + } + + @Override + public boolean isValidMemberInGroupsAndVos(Long userId, Set<Long> vos, Set<Long> groups) { + final Set<Long> foundGroupIds = new HashSet<>(); + final Set<Long> foundVoIds = new HashSet<>(); + String dnPrefix = getDnPrefixForUserId(userId); + String[] attributes = new String[] { MEMBER_OF }; + EntryMapper<Void> mapper = e -> { + if (checkHasAttributes(e, attributes)) { + Attribute a = e.get(MEMBER_OF); + a.iterator().forEachRemaining(id -> { + String fullVal = id.getString(); + String[] parts = fullVal.split(",", 3); + + String groupId = parts[0]; + groupId = groupId.replace(PERUN_GROUP_ID + '=', ""); + foundGroupIds.add(Long.parseLong(groupId)); + String voIdStr = parts[1]; + voIdStr = voIdStr.replace(PERUN_VO_ID + '=', ""); + foundVoIds.add(Long.parseLong(voIdStr)); + }); + } + return null; + }; + connectorLdap.lookup(dnPrefix, attributes, mapper); + + return PerunAdapter.decideAccess(foundVoIds, foundGroupIds, vos, groups); + } + + @Override + public boolean isUserInVo(Long userId, String voShortName) { + if (userId == null) { + throw new IllegalArgumentException("No userId"); + } else if (!StringUtils.hasText(voShortName)) { + throw new IllegalArgumentException("No voShortName"); + } + + String uniqueMember = getDnPrefixForUserId(userId) + ',' + this.connectorLdap.getBaseDN(); + FilterBuilder filter = and(equal(OBJECT_CLASS, PERUN_VO), equal(UNIQUE_MEMBER, uniqueMember), equal(O, voShortName)); + String[] attributes = new String[] { PERUN_VO_ID, O, DESCRIPTION }; + EntryMapper<Vo> mapper = e -> { + if (!checkHasAttributes(e, attributes)) { + return null; + } + + Long id = Long.valueOf(e.get(PERUN_VO_ID).getString()); + String shortNameVo = e.get(O).getString(); + String name = e.get(DESCRIPTION).getString(); + + return new Vo(id, name, shortNameVo); + }; + + Vo vo = connectorLdap.searchFirst(null, filter, SearchScope.ONELEVEL, attributes, mapper); + return vo != null; + } + + private List<Group> getGroups(Collection<?> objects, String objectAttribute) { + List<Group> result; + if (objects == null || objects.size() <= 0) { + result = new ArrayList<>(); + } else { + FilterBuilder filter; + if (objects.size() == 1) { + Object first = objects.toArray()[0]; + filter = and(equal(OBJECT_CLASS, PERUN_GROUP), equal(objectAttribute, String.valueOf(first))); + } else { + FilterBuilder[] partialFilters = new FilterBuilder[objects.size()]; + int i = 0; + for (Object obj: objects) { + partialFilters[i++] = equal(objectAttribute, String.valueOf(obj)); + } + filter = and(equal(OBJECT_CLASS, PERUN_GROUP), or(partialFilters)); + } + + String[] attributes = new String[]{PERUN_GROUP_ID, CN, DESCRIPTION, PERUN_UNIQUE_GROUP_NAME, + PERUN_VO_ID, PERUN_PARENT_GROUP_ID, UUID}; + + EntryMapper<Group> mapper = e -> { + if (!checkHasAttributes(e, new String[]{ + PERUN_GROUP_ID, CN, DESCRIPTION, PERUN_UNIQUE_GROUP_NAME, PERUN_VO_ID, UUID })) + { + return null; + } + + Long id = Long.valueOf(e.get(PERUN_GROUP_ID).getString()); + String name = e.get(CN).getString(); + String description = e.get(DESCRIPTION).getString(); + String uniqueName = e.get(PERUN_UNIQUE_GROUP_NAME).getString(); + Long voId = Long.valueOf(e.get(PERUN_VO_ID).getString()); + Long parentGroupId = null; + if (e.get(PERUN_PARENT_GROUP_ID) != null) { + parentGroupId = Long.valueOf(e.get(PERUN_PARENT_GROUP_ID).getString()); + } + String uuid = e.get(UUID).getString(); + + return new Group(id, parentGroupId, name, description, uniqueName,uuid, voId); + }; + + result = connectorLdap.search(null, filter, SearchScope.SUBTREE, attributes, mapper); + result = result.stream().filter(Objects::nonNull).collect(Collectors.toList()); + } + + return result; + } + + private Set<Long> getGroupIdsWhereUserIsMember(Long userId, Long voId) { + String dnPrefix = getDnPrefixForUserId(userId); + String[] attributes = new String[] { MEMBER_OF }; + EntryMapper<Set<Long>> mapper = e -> { + Set<Long> ids = new HashSet<>(); + if (checkHasAttributes(e, attributes)) { + Attribute a = e.get(MEMBER_OF); + a.iterator().forEachRemaining(id -> { + String fullVal = id.getString(); + String[] parts = fullVal.split(",", 3); + + String groupId = parts[0]; + groupId = groupId.replace(PERUN_GROUP_ID + '=', ""); + + String voIdStr = parts[1]; + voIdStr = voIdStr.replace(PERUN_VO_ID + '=', ""); + + if (voId == null || voId.equals(Long.parseLong(voIdStr))) { + ids.add(Long.parseLong(groupId)); + } + }); + } + + return ids; + }; + + return connectorLdap.lookup(dnPrefix, attributes, mapper); + } + + private String getDnPrefixForUserId(Long userId) { + return PERUN_USER_ID + '=' + userId + ',' + OU_PEOPLE; + } + + private Set<Long> getGroupIdsWithAccessToFacility(Long facilityId) { + FilterBuilder filter = and(equal(OBJECT_CLASS, PERUN_RESOURCE), equal(PERUN_FACILITY_ID, String.valueOf(facilityId))); + String[] attributes = new String[] { ASSIGNED_GROUP_ID }; + EntryMapper<Set<Long>> mapper = e -> { + Set<Long> ids = new HashSet<>(); + if (checkHasAttributes(e, attributes)) { + Attribute a = e.get(ASSIGNED_GROUP_ID); + if (a != null) { + a.iterator().forEachRemaining(id -> ids.add(Long.valueOf(id.getString()))); + } + } + + return ids; + }; + + List<Set<Long>> assignedGroupIdsAll = connectorLdap.search(null, filter, SearchScope.SUBTREE, attributes, mapper); + return assignedGroupIdsAll.stream() + .flatMap(Set::stream) + .collect(Collectors.toSet()); + } + + private Map<String, PerunAttributeValue> getAttributeValues(String dnPrefix, Collection<String> attrsToFetch, + PerunEntityType entity) { + Set<AttributeMapping> mappings = this.getMappingsForAttrNames(entity, attrsToFetch); + String[] attributes = this.getAttributesFromMappings(mappings); + + Map<String, PerunAttributeValue> res = new HashMap<>(); + if (attributes.length != 0) { + EntryMapper<Map<String, PerunAttributeValue>> mapper = attrValueMapper(mappings); + res = this.connectorLdap.lookup(dnPrefix, attributes, mapper); + } + + return res; + } + + private List<Group> getGroupsByUniqueGroupNames(Set<String> groupNames) { + List<Group> groups = getGroups(groupNames, PERUN_UNIQUE_GROUP_NAME); + groups = groups.stream().filter(Objects::nonNull).collect(Collectors.toList()); + + return groups; + } + + private boolean checkHasAttributes(Entry e, String[] attributes) { + if (e == null) { + return false; + } else if (attributes == null) { + return true; + } + + for (String attr: attributes) { + if (e.get(attr) == null) { + return false; + } + } + + return true; + } + + private EntryMapper<Map<String, PerunAttributeValue>> attrValueMapper(Set<AttributeMapping> attrMappings) { + return entry -> { + Map<String, PerunAttributeValue> resultMap = new LinkedHashMap<>(); + Map<String, Attribute> attrNamesMap = new HashMap<>(); + + for (Attribute attr : entry.getAttributes()) { + if (attr.isHumanReadable()) { + attrNamesMap.put(attr.getId(), attr); + } + } + + for (AttributeMapping mapping: attrMappings) { + if (mapping.getLdapName() == null || mapping.getLdapName().isEmpty()) { + continue; + } + String ldapAttrName = mapping.getLdapName(); + // the library always converts name of attribute to lowercase, therefore we need to convert it as well + Attribute attribute = attrNamesMap.getOrDefault(ldapAttrName.toLowerCase(), null); + PerunAttributeValue value = parseValue(attribute, mapping); + resultMap.put(mapping.getIdentifier(), value); + } + + return resultMap; + }; + } + + private PerunAttributeValue parseValue(Attribute attr, AttributeMapping mapping) { + PerunAttrValueType type = mapping.getAttrType(); + boolean isNull = (attr == null || attr.get() == null || attr.get().isNull()); + switch (type) { + case STRING: + return new PerunAttributeValue(mapping.getIdentifier(), PerunAttributeValue.STRING_TYPE, + isNull ? jsonNodeFactory.nullNode() : jsonNodeFactory.textNode(attr.get().getString())); + case INTEGER: + return new PerunAttributeValue(mapping.getIdentifier(), PerunAttributeValue.INTEGER_TYPE, + isNull ? jsonNodeFactory.nullNode() : jsonNodeFactory.numberNode(Long.parseLong(attr.get().getString()))); + case BOOLEAN: + return new PerunAttributeValue(mapping.getIdentifier(), PerunAttributeValue.BOOLEAN_TYPE, + isNull ? jsonNodeFactory.booleanNode(false) : jsonNodeFactory.booleanNode(Boolean.parseBoolean(attr.get().getString()))); + case ARRAY: + return new PerunAttributeValue(mapping.getIdentifier(), PerunAttributeValue.ARRAY_TYPE, + isNull ? jsonNodeFactory.arrayNode() : getArrNode(attr)); + case MAP_JSON: + return new PerunAttributeValue(mapping.getIdentifier(), PerunAttributeValue.MAP_TYPE, + isNull ? jsonNodeFactory.objectNode() : getMapNodeJson(attr)); + case MAP_KEY_VALUE: + return new PerunAttributeValue(mapping.getIdentifier(), PerunAttributeValue.MAP_TYPE, + isNull ? jsonNodeFactory.objectNode() : getMapNodeSeparator(attr, mapping.getSeparator())); + default: + throw new IllegalArgumentException("unrecognized type"); + } + + } + + private ObjectNode getMapNodeSeparator(Attribute attr, String separator) { + ObjectNode objectNode = jsonNodeFactory.objectNode(); + for (Value value : attr) { + if (value.getString() != null) { + String[] parts = value.getString().split(separator, 2); + objectNode.put(parts[0], parts[1]); + } + } + return objectNode; + } + + private ObjectNode getMapNodeJson(Attribute attr) { + String jsonStr = attr.get().getString(); + ObjectMapper objectMapper = new ObjectMapper(); + try { + return objectMapper.readValue(jsonStr, ObjectNode.class); + } catch (IOException e) { + throw new InconvertibleValueException("Could not parse value"); + } + } + + private ArrayNode getArrNode(Attribute attr) { + ArrayNode arrayNode = jsonNodeFactory.arrayNode(attr.size()); + for (Value value : attr) { + arrayNode.add(value.getString()); + } + return arrayNode; + } + + private boolean isNumber(String s) { + try { + Long.parseLong(s); + return true; + } catch (NumberFormatException | NullPointerException e) { + return false; + } + } + + private Set<AttributeMapping> getMappingsForAttrNames(PerunEntityType entity, Collection<String> attrsToFetch) { + Set<AttributeMapping> mappings; + switch (entity) { + case USER: + mappings = this.getUserAttributesMappingService() + .getMappingsByIdentifiers(attrsToFetch); + break; + case FACILITY: + mappings = this.getFacilityAttributesMappingService() + .getMappingsByIdentifiers(attrsToFetch); + break; + case VO: + mappings = this.getVoAttributesMappingService() + .getMappingsByIdentifiers(attrsToFetch); + break; + case GROUP: + mappings = this.getGroupAttributesMappingService() + .getMappingsByIdentifiers(attrsToFetch); + break; + case RESOURCE: + mappings = this.getResourceAttributesMappingService() + .getMappingsByIdentifiers(attrsToFetch); + break; + default: + log.error("Unknown ENTITY {}", entity); + mappings = new HashSet<>(); + break; + } + + return mappings; + } + + private String[] getAttributesFromMappings(Set<AttributeMapping> mappings) { + return mappings.stream() + .map(AttributeMapping::getLdapName) + .distinct() + .collect(Collectors.toList()) + .toArray(new String[] {}); + } + + private Set<String> getFacilityCapabilities(Facility facility, String capabilitiesAttrName) { + Set<String> result = new HashSet<>(); + PerunAttributeValue attrVal = getFacilityAttributeValue(facility, capabilitiesAttrName); + if (attrVal != null && !attrVal.isNullValue() && attrVal.valueAsList() != null) { + result = new HashSet<>(attrVal.valueAsList()); + } + + return result; + } + + private Set<String> getCapabilities(Facility facility, String facilityCapabilitiesAttrName, + String resourceCapabilitiesAttrName, FilterBuilder[] parts) { + String facilityDN = PERUN_FACILITY_ID + '=' + facility.getId() + ',' + connectorLdap.getBaseDN(); + FilterBuilder filter = and(equal(OBJECT_CLASS, PERUN_RESOURCE), equal(PERUN_FACILITY_DN, facilityDN), or(parts)); + AttributeMapping capabilitiesMapping = getResourceAttributesMappingService().getMappingByIdentifier(resourceCapabilitiesAttrName); + String[] attributes = new String[] { capabilitiesMapping.getLdapName(), ASSIGNED_GROUP_ID }; + EntryMapper<Set<String>> mapper = e -> { + Set<String> capabilities = new HashSet<>(); + if (!checkHasAttributes(e, attributes)) { + return new HashSet<>(); + } + + Attribute capabilitiesAttr = e.get(capabilitiesMapping.getLdapName()); + if (capabilitiesAttr != null) { + capabilitiesAttr.iterator().forEachRemaining(v -> capabilities.add(v.getString())); + } + + return capabilities; + }; + List<Set<String>> resourceCaps = connectorLdap.search(null, filter, SearchScope.SUBTREE, attributes, mapper); + Set<String> capabilities = new HashSet<>(); + boolean includeFacilityCapabilities = false; + if (resourceCaps != null && !resourceCaps.isEmpty()) { + // if the mapper returns at least one entry, user is a member of some group assigned to the facility + includeFacilityCapabilities = true; + resourceCaps.stream() + .filter(Objects::nonNull) + .forEach(capabilities::addAll); + } + + if (facilityCapabilitiesAttrName != null && includeFacilityCapabilities ) { + Set<String> facilityCapabilities = this.getFacilityCapabilities(facility, facilityCapabilitiesAttrName); + capabilities.addAll(facilityCapabilities); + } + + return capabilities; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterLdapConstants.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterLdapConstants.java new file mode 100644 index 000000000..9ada261cf --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterLdapConstants.java @@ -0,0 +1,43 @@ +package cz.muni.ics.oidc.server.adapters.impl; + +public class PerunAdapterLdapConstants { + + // COMMON + public static final String O = "o"; + public static final String CN = "cn"; + public static final String SN = "sn"; + public static final String DESCRIPTION = "description"; + public static final String OBJECT_CLASS = "objectClass"; + public static final String OU_PEOPLE = "ou=People"; + public static final String UUID = "uuid"; + + // USER + public static final String PERUN_USER = "perunUser"; + public static final String PERUN_USER_ID = "perunUserId"; + public static final String GIVEN_NAME = "givenName"; + public static final String MEMBER_OF = "memberOf"; + public static final String EDU_PERSON_PRINCIPAL_NAMES = "eduPersonPrincipalNames"; + + // GROUP + public static final String PERUN_GROUP = "perunGroup"; + public static final String PERUN_GROUP_ID = "perunGroupId"; + public static final String PERUN_PARENT_GROUP_ID = "perunParentGroupId"; + public static final String PERUN_UNIQUE_GROUP_NAME = "perunUniqueGroupName"; + public static final String UNIQUE_MEMBER = "uniqueMember"; + + // VO + public static final String PERUN_VO = "perunVO"; + public static final String PERUN_VO_ID = "perunVoId"; + public static final String MEMBER_OF_PERUN_VO = "memberOfPerunVo"; + + // RESOURCE + public static final String PERUN_RESOURCE = "perunResource"; + public static final String PERUN_RESOURCE_ID = "perunResourceId"; + + // FACILITY + public static final String PERUN_FACILITY = "perunFacility"; + public static final String PERUN_FACILITY_DN = "perunFacilityDn"; + public static final String PERUN_FACILITY_ID = "perunFacilityId"; + public static final String ASSIGNED_GROUP_ID = "assignedGroupId"; + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterRpc.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterRpc.java new file mode 100644 index 000000000..0bd7c51f7 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterRpc.java @@ -0,0 +1,1312 @@ +package cz.muni.ics.oidc.server.adapters.impl; + +import static cz.muni.ics.oidc.models.PerunAttributeValue.STRING_TYPE; +import static cz.muni.ics.oidc.models.enums.MemberStatus.VALID; +import static cz.muni.ics.oidc.server.connectors.PerunConnectorRpc.ATTRIBUTES_MANAGER; +import static cz.muni.ics.oidc.server.connectors.PerunConnectorRpc.FACILITIES_MANAGER; +import static cz.muni.ics.oidc.server.connectors.PerunConnectorRpc.GROUPS_MANAGER; +import static cz.muni.ics.oidc.server.connectors.PerunConnectorRpc.MEMBERS_MANAGER; +import static cz.muni.ics.oidc.server.connectors.PerunConnectorRpc.REGISTRAR_MANAGER; +import static cz.muni.ics.oidc.server.connectors.PerunConnectorRpc.RESOURCES_MANAGER; +import static cz.muni.ics.oidc.server.connectors.PerunConnectorRpc.USERS_MANAGER; +import static cz.muni.ics.oidc.server.connectors.PerunConnectorRpc.VOS_MANAGER; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.NullNode; +import cz.muni.ics.oidc.models.AttributeMapping; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.Group; +import cz.muni.ics.oidc.models.Member; +import cz.muni.ics.oidc.models.Model; +import cz.muni.ics.oidc.models.PerunAttribute; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.models.Resource; +import cz.muni.ics.oidc.models.UserExtSource; +import cz.muni.ics.oidc.models.Vo; +import cz.muni.ics.oidc.models.enums.MemberStatus; +import cz.muni.ics.oidc.models.enums.PerunEntityType; +import cz.muni.ics.oidc.models.mappers.RpcMapper; +import cz.muni.ics.oidc.server.PerunPrincipal; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.adapters.PerunAdapterMethods; +import cz.muni.ics.oidc.server.adapters.PerunAdapterMethodsRpc; +import cz.muni.ics.oidc.server.connectors.Affiliation; +import cz.muni.ics.oidc.server.connectors.PerunConnectorRpc; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +/** + * Interface for fetching data from Perun via RPC + * + * @author Martin Kuba makub@ics.muni.cz + * @author Dominik František Bučík bucik@ics.muni.cz + * @author Peter Jancus jancus@ics.muni.cz + */ +public class PerunAdapterRpc extends PerunAdapterWithMappingServices implements PerunAdapterMethods, PerunAdapterMethodsRpc { + + private final static Logger log = LoggerFactory.getLogger(PerunAdapterRpc.class); + + private PerunConnectorRpc connectorRpc; + + private String oidcClientIdAttr; + private String oidcCheckMembershipAttr; + private String orgUrlAttr; + private String affiliationsAttr; + + public void setConnectorRpc(PerunConnectorRpc connectorRpc) { + this.connectorRpc = connectorRpc; + } + + public void setOidcClientIdAttr(String oidcClientIdAttr) { + this.oidcClientIdAttr = oidcClientIdAttr; + } + + public void setOidcCheckMembershipAttr(String oidcCheckMembershipAttr) { + this.oidcCheckMembershipAttr = oidcCheckMembershipAttr; + } + + public void setOrgUrlAttr(String orgUrlAttr) { + this.orgUrlAttr = orgUrlAttr; + } + + public void setAffiliationsAttr(String affiliationsAttr) { + this.affiliationsAttr = affiliationsAttr; + } + + @Override + public PerunUser getPreauthenticatedUserId(PerunPrincipal perunPrincipal) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + Map<String, Object> map = new LinkedHashMap<>(); + map.put("extLogin", perunPrincipal.getExtLogin()); + map.put("extSourceName", perunPrincipal.getExtSourceName()); + + JsonNode response = connectorRpc.post(USERS_MANAGER, "getUserByExtSourceNameAndExtLogin", map); + return RpcMapper.mapPerunUser(response); + } + + @Override + public Facility getFacilityByClientId(String clientId) { + if (!this.connectorRpc.isEnabled()) { + return null; + } else if (!StringUtils.hasText(clientId)) { + return null; + } + + AttributeMapping mapping = this.getFacilityAttributesMappingService().getMappingByIdentifier(oidcClientIdAttr); + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("attributeName", mapping.getRpcName()); + map.put("attributeValue", clientId); + JsonNode jsonNode = connectorRpc.post(FACILITIES_MANAGER, "getFacilitiesByAttribute", map); + + return (jsonNode.size() > 0) ? RpcMapper.mapFacility(jsonNode.get(0)) : null; + } + + @Override + public boolean isMembershipCheckEnabledOnFacility(Facility facility) { + if (!this.connectorRpc.isEnabled()) { + return false; + } + + AttributeMapping mapping = this.getFacilityAttributesMappingService().getMappingByIdentifier(oidcCheckMembershipAttr); + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("facility", facility.getId()); + map.put("attributeName", mapping.getRpcName()); + JsonNode res = connectorRpc.post(ATTRIBUTES_MANAGER, "getAttribute", map); + + return res.get("value").asBoolean(false); + } + + @Override + public boolean canUserAccessBasedOnMembership(Facility facility, Long userId) { + if (!this.connectorRpc.isEnabled()) { + return true; + } + + List<Group> activeGroups = getGroupsWhereUserIsActive(facility, userId); + return !activeGroups.isEmpty(); + } + + @Override + public Map<Vo, List<Group>> getGroupsForRegistration(Facility facility, Long userId, List<String> voShortNames) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + List<Vo> vos = getVosByShortNames(voShortNames); + Map<Long, Vo> vosMap = convertVoListToMap(vos); + List<Member> userMembers = getMembersByUser(userId); + userMembers = new ArrayList<>(new HashSet<>(userMembers)); + + //Filter out vos where member is other than valid or expired. These vos cannot be used for registration + Map<Long, MemberStatus> memberVoStatuses = convertMembersListToStatusesMap(userMembers); + Map<Long, Vo> vosForRegistration = new HashMap<>(); + for (Map.Entry<Long, Vo> entry : vosMap.entrySet()) { + if (memberVoStatuses.containsKey(entry.getKey())) { + MemberStatus status = memberVoStatuses.get(entry.getKey()); + if (VALID.equals(status) || MemberStatus.EXPIRED.equals(status)) { + vosForRegistration.put(entry.getKey(), entry.getValue()); + } + } else { + vosForRegistration.put(entry.getKey(), entry.getValue()); + } + } + + // filter groups only if their VO is in the allowed VOs and if they have registration form + List<Group> allowedGroups = getAllowedGroups(facility); + List<Group> groupsForRegistration = allowedGroups.stream() + .filter(group -> vosForRegistration.containsKey(group.getVoId()) && hasApplicationForm(group)) + .collect(Collectors.toList()); + + // create map for processing + Map<Vo, List<Group>> result = new HashMap<>(); + for (Group group : groupsForRegistration) { + Vo vo = vosMap.get(group.getVoId()); + if (!result.containsKey(vo)) { + result.put(vo, new ArrayList<>()); + } + List<Group> list = result.get(vo); + list.add(group); + } + + return result; + } + + @Override + public boolean groupWhereCanRegisterExists(Facility facility) { + if (!this.connectorRpc.isEnabled()) { + return false; + } + + List<Group> allowedGroups = getAllowedGroups(facility); + + if (!allowedGroups.isEmpty()) { + for (Group group : allowedGroups) { + if (hasApplicationForm(group)) { + return true; + } + } + } + + return false; + } + + @Override + public boolean isUserInGroup(Long userId, Long groupId) { + if (!this.connectorRpc.isEnabled()) { + return false; + } + + Map<String, Object> groupParams = new LinkedHashMap<>(); + groupParams.put("id", groupId); + JsonNode groupResponse = connectorRpc.post(GROUPS_MANAGER, "getGroupById", groupParams); + Group group = RpcMapper.mapGroup(groupResponse); + + Map<String, Object> memberParams = new LinkedHashMap<>(); + memberParams.put("vo", group.getVoId()); + memberParams.put("user", userId); + JsonNode memberResponse = connectorRpc.post(MEMBERS_MANAGER, "getMemberByUser", memberParams); + Member member = RpcMapper.mapMember(memberResponse); + + Map<String, Object> isGroupMemberParams = new LinkedHashMap<>(); + isGroupMemberParams.put("group", groupId); + isGroupMemberParams.put("member", member.getId()); + JsonNode res = connectorRpc.post(GROUPS_MANAGER, "isGroupMember", isGroupMemberParams); + + return res.asBoolean(false); + } + + @Override + public boolean setUserAttribute(Long userId, PerunAttribute attribute) { + if (!this.connectorRpc.isEnabled()) { + return true; + } + + JsonNode attributeJson = attribute.toJson(); + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("user", userId); + map.put("attribute", attributeJson); + + JsonNode response = connectorRpc.post(ATTRIBUTES_MANAGER, "setAttribute", map); + return (response == null || response.isNull() || response instanceof NullNode); + } + + @Override + public List<Affiliation> getUserExtSourcesAffiliations(Long userId) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + List<UserExtSource> userExtSources = getUserExtSources(userId); + List<Affiliation> affiliations = new ArrayList<>(); + + AttributeMapping affMapping = new AttributeMapping("affMapping", affiliationsAttr, "", PerunAttributeValue.ARRAY_TYPE); + AttributeMapping orgUrlMapping = new AttributeMapping("orgUrl", orgUrlAttr, "", STRING_TYPE); + Set<AttributeMapping> attributeMappings = new HashSet<>(Arrays.asList(affMapping, orgUrlMapping)); + + for (UserExtSource ues : userExtSources) { + if ("cz.metacentrum.perun.core.impl.ExtSourceIdp".equals(ues.getExtSource().getType())) { + Map<String, PerunAttributeValue> uesAttrValues = getUserExtSourceAttributeValues(ues.getId(), attributeMappings); + + long asserted = ues.getLastAccess().getTime() / 1000L; + + String orgUrl = uesAttrValues.get(orgUrlMapping.getIdentifier()).valueAsString(); + String affs = uesAttrValues.get(affMapping.getIdentifier()).valueAsString(); + if (affs != null) { + for (String aff : affs.split(";")) { + String source = ( (orgUrl != null) ? orgUrl : ues.getExtSource().getName() ); + Affiliation affiliation = new Affiliation(source, aff, asserted); + log.debug("found {} from IdP {} with orgURL {} asserted at {}", aff, ues.getExtSource().getName(), + orgUrl, asserted); + affiliations.add(affiliation); + } + } + } + } + + return affiliations; + } + + @Override + public List<Affiliation> getGroupAffiliations(Long userId, String groupAffiliationsAttr) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + List<Affiliation> affiliations = new ArrayList<>(); + + List<Member> userMembers = getMembersByUser(userId); + for (Member member : userMembers) { + if (VALID.equals(member.getStatus())) { + List<Group> memberGroups = getMemberGroups(member.getId()); + for (Group group : memberGroups) { + PerunAttributeValue attrValue = this.getGroupAttributeValue(group, groupAffiliationsAttr); + if (attrValue != null && attrValue.valueAsString() != null) { + long linuxTime = System.currentTimeMillis() / 1000L; + for (String value : attrValue.valueAsList()) { + Affiliation affiliation = new Affiliation(null, value, linuxTime); + log.debug("found {} on group {}", value, group.getName()); + affiliations.add(affiliation); + } + } + } + } + } + + return affiliations; + } + + @Override + public List<String> getGroupsAssignedToResourcesWithUniqueNames(Facility facility) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + List<Resource> resources = getAssignedResources(facility); + List<String> result = new ArrayList<>(); + + String voShortName = "urn:perun:group:attribute-def:virt:voShortName"; + + for (Resource res : resources) { + List<Group> groups = getRichGroupsAssignedToResourceWithAttributesByNames(res, Collections.singletonList(voShortName)); + + for (Group group : groups) { + if (group.getAttributeByUrnName(voShortName) != null && + group.getAttributeByUrnName(voShortName).hasNonNull("value")) { + String value = group.getAttributeByUrnName(voShortName).get("value").textValue(); + group.setUniqueGroupName(value + ":" + group.getName()); + result.add(group.getUniqueGroupName()); + } + } + } + + return result; + } + + @Override + public Map<String, PerunAttribute> getEntitylessAttributes(String attributeName) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + Map<String, Object> attrNameMap = new LinkedHashMap<>(); + attrNameMap.put("attrName", attributeName); + JsonNode entitylessAttributesJson = connectorRpc.post(ATTRIBUTES_MANAGER, "getEntitylessAttributes", attrNameMap); + + Long attributeDefinitionId = RpcMapper.mapAttribute(entitylessAttributesJson.get(0)).getId(); + + Map<String, Object> attributeDefinitionIdMap = new LinkedHashMap<>(); + attributeDefinitionIdMap.put("attributeDefinition", attributeDefinitionId); + JsonNode entitylessKeysJson = connectorRpc.post(ATTRIBUTES_MANAGER, "getEntitylessKeys", attributeDefinitionIdMap); + + Map<String, PerunAttribute> result = new LinkedHashMap<>(); + + for(int i = 0; i < entitylessKeysJson.size(); i++) { + result.put(entitylessKeysJson.get(i).asText(), RpcMapper.mapAttribute(entitylessAttributesJson.get(i))); + } + + if (result.size() == 0) { + return null; + } + + return result; + } + + @Override + public Vo getVoByShortName(String shortName) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + Map<String, Object> params = new LinkedHashMap<>(); + params.put("shortName", shortName); + + JsonNode jsonNode = connectorRpc.post(VOS_MANAGER, "getVoByShortName", params); + return RpcMapper.mapVo(jsonNode); + } + + @Override + public Map<String, PerunAttributeValue> getUserAttributeValues(PerunUser user, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return this.getUserAttributeValues(user.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getUserAttributeValues(Long userId, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + Map<String, PerunAttribute> userAttributes = this.getUserAttributes(userId, attrsToFetch); + return extractValues(userAttributes); + } + + @Override + public PerunAttributeValue getUserAttributeValue(PerunUser user, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getUserAttributeValue(user.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getUserAttributeValue(Long userId, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getUserAttribute(userId, attrToFetch).toPerunAttributeValue(); + } + + @Override + public Map<String, PerunAttributeValue> getFacilityAttributeValues(Facility facility, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return this.getFacilityAttributeValues(facility.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getFacilityAttributeValues(Long facilityId, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + Map<String, PerunAttribute> facilityAttributes = this.getFacilityAttributes(facilityId, attrsToFetch); + return extractValues(facilityAttributes); + } + + @Override + public PerunAttributeValue getFacilityAttributeValue(Facility facility, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getFacilityAttributeValue(facility.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getFacilityAttributeValue(Long facilityId, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getFacilityAttribute(facilityId, attrToFetch).toPerunAttributeValue(); + } + + @Override + public Map<String, PerunAttributeValue> getVoAttributeValues(Vo vo, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return this.getVoAttributeValues(vo.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getVoAttributeValues(Long voId, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + Map<String, PerunAttribute> voAttributes = this.getVoAttributes(voId, attrsToFetch); + return extractValues(voAttributes); + } + + @Override + public PerunAttributeValue getVoAttributeValue(Vo vo, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getVoAttributeValue(vo.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getVoAttributeValue(Long voId, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getVoAttribute(voId, attrToFetch).toPerunAttributeValue(); + } + + @Override + public Map<String, PerunAttributeValue> getGroupAttributeValues(Group group, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return this.getGroupAttributeValues(group.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getGroupAttributeValues(Long groupId, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + Map<String, PerunAttribute> groupAttributes = this.getGroupAttributes(groupId, attrsToFetch); + return extractValues(groupAttributes); + } + + @Override + public PerunAttributeValue getGroupAttributeValue(Group group, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getGroupAttributeValue(group.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getGroupAttributeValue(Long groupId, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getGroupAttribute(groupId, attrToFetch).toPerunAttributeValue(); + } + + @Override + public Map<String, PerunAttributeValue> getResourceAttributeValues(Resource resource, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return this.getResourceAttributeValues(resource.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttributeValue> getResourceAttributeValues(Long resourceId, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + Map<String, PerunAttribute> resourceAttributes = this.getResourceAttributes(resourceId, attrsToFetch); + return extractValues(resourceAttributes); + } + + @Override + public PerunAttributeValue getResourceAttributeValue(Resource resource, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getResourceAttributeValue(resource.getId(), attrToFetch); + } + + @Override + public PerunAttributeValue getResourceAttributeValue(Long resourceId, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getResourceAttribute(resourceId, attrToFetch).toPerunAttributeValue(); + } + + @Override + public Map<String, PerunAttribute> getFacilityAttributes(Facility facility, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return this.getFacilityAttributes(facility.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttribute> getFacilityAttributes(Long facilityId, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return getAttributes(PerunEntityType.FACILITY, facilityId, attrsToFetch); + } + + @Override + public PerunAttribute getFacilityAttribute(Facility facility, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getFacilityAttribute(facility.getId(), attrToFetch); + } + + @Override + public PerunAttribute getFacilityAttribute(Long facilityId, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return getAttribute(PerunEntityType.FACILITY, facilityId, attrToFetch); + } + + @Override + public Map<String, PerunAttribute> getGroupAttributes(Group group, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return this.getGroupAttributes(group.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttribute> getGroupAttributes(Long groupId, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return getAttributes(PerunEntityType.GROUP, groupId, attrsToFetch); + } + + @Override + public PerunAttribute getGroupAttribute(Group group, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getGroupAttribute(group.getId(), attrToFetch); + } + + @Override + public PerunAttribute getGroupAttribute(Long groupId, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return getAttribute(PerunEntityType.GROUP, groupId, attrToFetch); + } + + @Override + public Map<String, PerunAttribute> getUserAttributes(PerunUser user, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return this.getUserAttributes(user.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttribute> getUserAttributes(Long userId, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return getAttributes(PerunEntityType.USER, userId, attrsToFetch); + } + + @Override + public PerunAttribute getUserAttribute(PerunUser user, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getUserAttribute(user.getId(), attrToFetch); + } + + @Override + public PerunAttribute getUserAttribute(Long userId, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return getAttribute(PerunEntityType.USER, userId, attrToFetch); + } + + @Override + public Map<String, PerunAttribute> getVoAttributes(Vo vo, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return this.getVoAttributes(vo.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttribute> getVoAttributes(Long voId, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return getAttributes(PerunEntityType.VO, voId, attrsToFetch); + } + + @Override + public PerunAttribute getVoAttribute(Vo vo, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getVoAttribute(vo.getId(), attrToFetch); + } + + @Override + public PerunAttribute getVoAttribute(Long voId, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return getAttribute(PerunEntityType.VO, voId, attrToFetch); + } + + @Override + public Map<String, PerunAttribute> getResourceAttributes(Resource resource, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return this.getResourceAttributes(resource.getId(), attrsToFetch); + } + + @Override + public Map<String, PerunAttribute> getResourceAttributes(Long resourceId, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + return getAttributes(PerunEntityType.RESOURCE, resourceId, attrsToFetch); + } + + @Override + public PerunAttribute getResourceAttribute(Resource resource, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return this.getResourceAttribute(resource.getId(), attrToFetch); + } + + @Override + public PerunAttribute getResourceAttribute(Long resourceId, String attrToFetch) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + return getAttribute(PerunEntityType.RESOURCE, resourceId, attrToFetch); + } + + @Override + public Set<String> getCapabilities(Facility facility, Set<String> groupNames, + String facilityCapabilitiesAttrName, + String resourceCapabilitiesAttrName) + { + if (!this.connectorRpc.isEnabled()) { + return new HashSet<>(); + } + + if (facility == null) { + return new HashSet<>(); + } + + Set<String> capabilities = new HashSet<>(); + Set<String> resourceGroupNames = new HashSet<>(); + + if (null != resourceCapabilitiesAttrName) { + List<Resource> resources = this.getAssignedRichResources(facility); + for (Resource resource : resources) { + PerunAttributeValue attrValue = this.getResourceAttributeValue(resource.getId(), resourceCapabilitiesAttrName); + + List<String> resourceCapabilities = attrValue.valueAsList(); + if (resourceCapabilities == null || resourceCapabilities.size() == 0) { + continue; + } + List<Group> groups = this.getAssignedGroups(resource.getId()); + for (Group group : groups) { + resourceGroupNames.add(group.getName()); + String groupName = group.getName(); + if (resource.getVo() != null) { + groupName = resource.getVo().getShortName() + ':' + groupName; + } + group.setUniqueGroupName(groupName); + + if (groupNames.contains(groupName)) { + log.trace("Group [{}] found in users groups, add capabilities [{}]", groupName, resourceCapabilities); + capabilities.addAll(resourceCapabilities); + } else { + log.trace("Group [{}] not found in users groups, continue to the next one", groupName); + } + } + } + } + + if (null != facilityCapabilitiesAttrName && !Collections.disjoint(groupNames, resourceGroupNames)) { + Set<String> facilityCapabilities = this.getFacilityCapabilities(facility, facilityCapabilitiesAttrName); + capabilities.addAll(facilityCapabilities); + } + + return capabilities; + } + + @Override + public Set<String> getCapabilities(Facility facility, Map<Long, String> idToGnameMap, + String facilityCapabilitiesAttrName, String resourceCapabilitiesAttrName) + { + if (!this.connectorRpc.isEnabled()) { + return new HashSet<>(); + } + + if (facility == null) { + return new HashSet<>(); + } + + return this.getCapabilities(facility, new HashSet<>(idToGnameMap.values()), facilityCapabilitiesAttrName, + resourceCapabilitiesAttrName); + } + + @Override + public Set<Group> getGroupsWhereUserIsActiveWithUniqueNames(Long facilityId, Long userId) { + if (!this.connectorRpc.isEnabled()) { + return new HashSet<>(); + } + + Set<Group> groups = this.getGroupsWhereUserIsActive(facilityId, userId); + + Map<Long, String> voIdToShortNameMap = new HashMap<>(); + groups.forEach(g -> { + if (!voIdToShortNameMap.containsKey(g.getVoId())) { + Vo vo = this.getVoById(g.getVoId()); + if (vo != null) { + voIdToShortNameMap.put(vo.getId(), vo.getShortName()); + } + } + g.setUniqueGroupName(voIdToShortNameMap.get(g.getVoId()) + ':' + g.getName()); + }); + + return groups; + } + + @Override + public Set<Long> getUserGroupsIds(Long userId, Long voId) { + if (!this.connectorRpc.isEnabled()) { + return new HashSet<>(); + } + + Member member = getMemberByUser(userId, voId); + Set<Long> groups = new HashSet<>(); + if (member != null) { + groups = getMemberGroups(member.getId()).stream().map(Group::getId).collect(Collectors.toSet()); + } + + return groups; + } + + @Override + public boolean isValidMemberInGroupsAndVos(Long userId, Set<Long> mandatoryVos, Set<Long> mandatoryGroups, + Set<Long> envVos, Set<Long> envGroups) { + List<Member> members = getMembersByUser(userId); + Set<Long> foundVoIds = new HashSet<>(); + Set<Long> foundGroupIds = new HashSet<>(); + boolean skipGroups = mandatoryGroups.isEmpty() && envGroups.isEmpty(); + for (Member m: members) { + if (MemberStatus.VALID.equals(m.getStatus())) { + foundVoIds.add(m.getVoId()); + } + if (!skipGroups) { + foundGroupIds.addAll(getMemberGroups(m.getId()).stream().map(Model::getId).collect(Collectors.toList())); + } + } + + return PerunAdapter.decideAccess(foundVoIds, foundGroupIds, mandatoryVos, mandatoryGroups, envVos, envGroups); + } + + @Override + public boolean isValidMemberInGroupsAndVos(Long userId, Set<Long> vos, Set<Long> groups) { + List<Member> members = getMembersByUser(userId); + Set<Long> foundVoIds = new HashSet<>(); + Set<Long> foundGroupIds = new HashSet<>(); + boolean skipGroups = groups.isEmpty(); + + for (Member m: members) { + if (MemberStatus.VALID.equals(m.getStatus())) { + foundVoIds.add(m.getVoId()); + } + if (!skipGroups) { + foundGroupIds.addAll(getMemberGroups(m.getId()).stream().map(Model::getId).collect(Collectors.toList())); + } + } + + return PerunAdapter.decideAccess(foundVoIds, foundGroupIds, vos, groups); + } + + @Override + public boolean isUserInVo(Long userId, String voShortName) { + if (userId == null) { + throw new IllegalArgumentException("No userId"); + } else if (!StringUtils.hasText(voShortName)) { + throw new IllegalArgumentException("No voShortName"); + } + + Vo vo = getVoByShortName(voShortName); + if (vo == null || vo.getId() == null) { + log.debug("isUserInVo - No VO found, returning false"); + return false; + } + try { + Member member = getMemberByUser(userId, vo.getId()); + if (member == null) { + log.debug("isUserInVo - No member found, returning false"); + return false; + } + return VALID.equals(member.getStatus()); + } catch (Exception e) { + log.debug("isUserInVo - caught exception, probably user is not a member"); + log.trace("{}", e.getMessage(), e); + return false; + } + } + + @Override + public boolean hasApplicationForm(String voShortName) { + if (!this.connectorRpc.isEnabled()) { + return false; + } + + Vo vo = getVoByShortName(voShortName); + if (vo == null || vo.getId() == null) { + return false; + } + return hasApplicationForm(vo.getId()); + } + + private Member getMemberByUser(Long userId, Long voId) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + Map<String, Object> params = new LinkedHashMap<>(); + params.put("user", userId); + params.put("vo", voId); + JsonNode jsonNode = connectorRpc.post(MEMBERS_MANAGER, "getMemberByUser", params); + + return RpcMapper.mapMember(jsonNode); + } + + private Set<Group> getGroupsWhereUserIsActive(Long facilityId, Long userId) { + if (!this.connectorRpc.isEnabled()) { + return new HashSet<>(); + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("facility", facilityId); + map.put("user", userId); + JsonNode res = connectorRpc.post(USERS_MANAGER, "getGroupsWhereUserIsActive", map); + + return new HashSet<>(RpcMapper.mapGroups(res)); + } + + private Vo getVoById(Long voId) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("id", voId); + + JsonNode res = connectorRpc.post(VOS_MANAGER, "getVoById", map); + return RpcMapper.mapVo(res); + } + + private List<Group> getAssignedGroups(Long resourceId) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + Map<String, Object> params = new LinkedHashMap<>(); + params.put("resource", resourceId); + + JsonNode response = connectorRpc.post(RESOURCES_MANAGER, "getAssignedGroups", params); + + return RpcMapper.mapGroups(response); + } + + private Map<String, PerunAttributeValue> extractValues(Map<String, PerunAttribute> attributeMap) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + Map<String, PerunAttributeValue> resultMap = new LinkedHashMap<>(); + for (Map.Entry<String, PerunAttribute> attrPair: attributeMap.entrySet()) { + String attrName = attrPair.getKey(); + PerunAttribute attr = attrPair.getValue(); + if (attr != null) { + resultMap.put(attrName, attr.toPerunAttributeValue()); + } + } + + return resultMap; + } + + private Map<String, PerunAttribute> getAttributes(PerunEntityType entity, Long entityId, Collection<String> attrsToFetch) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } else if (attrsToFetch == null || attrsToFetch.isEmpty()) { + return new HashMap<>(); + } + + Set<AttributeMapping> mappings; + switch (entity) { + case USER: mappings = this.getUserAttributesMappingService() + .getMappingsByIdentifiers(attrsToFetch); + break; + case FACILITY: mappings = this.getFacilityAttributesMappingService() + .getMappingsByIdentifiers(attrsToFetch); + break; + case VO: mappings = this.getVoAttributesMappingService() + .getMappingsByIdentifiers(attrsToFetch); + break; + case GROUP: mappings = this.getGroupAttributesMappingService() + .getMappingsByIdentifiers(attrsToFetch); + break; + case RESOURCE: mappings = this.getResourceAttributesMappingService() + .getMappingsByIdentifiers(attrsToFetch); + break; + default: mappings = new HashSet<>(); + break; + } + + List<String> rpcNames = mappings.stream().map(AttributeMapping::getRpcName).collect(Collectors.toList()); + + Map<String, Object> map = new LinkedHashMap<>(); + map.put(entity.toString().toLowerCase(), entityId); + map.put("attrNames", rpcNames); + + JsonNode res = connectorRpc.post(ATTRIBUTES_MANAGER, "getAttributes", map); + return RpcMapper.mapAttributes(res, mappings); + } + + private List<Group> getMemberGroups(Long memberId) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("member", memberId); + + JsonNode response = connectorRpc.post(GROUPS_MANAGER, "getMemberGroups", map); + return RpcMapper.mapGroups(response); + } + + private List<Member> getMembersByUser(Long userId) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + Map<String, Object> params = new LinkedHashMap<>(); + params.put("user", userId); + JsonNode jsonNode = connectorRpc.post(MEMBERS_MANAGER, "getMembersByUser", params); + + return RpcMapper.mapMembers(jsonNode); + } + + private List<Vo> getVosByShortNames(List<String> voShortNames) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + List<Vo> vos = new ArrayList<>(); + for (String shortName : voShortNames) { + Vo vo = getVoByShortName(shortName); + vos.add(vo); + } + + return vos; + } + + private Map<Long, MemberStatus> convertMembersListToStatusesMap(List<Member> userMembers) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + Map<Long, MemberStatus> res = new HashMap<>(); + for (Member m : userMembers) { + res.put(m.getVoId(), m.getStatus()); + } + + return res; + } + + private Map<String, PerunAttributeValue> getUserExtSourceAttributeValues(Long uesId, Set<AttributeMapping> attrMappings) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("userExtSource", uesId); + map.put("attrNames", attrMappings.stream().map(AttributeMapping::getRpcName).collect(Collectors.toList())); + + JsonNode response = connectorRpc.post(ATTRIBUTES_MANAGER, "getAttributes", map); + Map<String, PerunAttribute> attributeMap = RpcMapper.mapAttributes(response, attrMappings); + return extractValues(attributeMap); + } + + private List<Group> getAllowedGroups(Facility facility) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("facility", facility.getId()); + JsonNode jsonNode = connectorRpc.post(FACILITIES_MANAGER, "getAllowedGroups", map); + List<Group> result = new ArrayList<>(); + for (int i = 0; i < jsonNode.size(); i++) { + JsonNode groupNode = jsonNode.get(i); + result.add(RpcMapper.mapGroup(groupNode)); + } + + return result; + } + + private boolean hasApplicationForm(Group group) { + if (!this.connectorRpc.isEnabled()) { + return false; + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("group", group.getId()); + try { + if (group.getName().equalsIgnoreCase("members")) { + log.debug("hasApplicationForm({}) continues to call regForm for VO {}", group, group.getVoId()); + return hasApplicationForm(group.getVoId()); + } else { + connectorRpc.post(REGISTRAR_MANAGER, "getApplicationForm", map); + } + } catch (Exception e) { + // when group does not have form exception is thrown. Every error thus is supposed as group without form + // this method will be used after calling other RPC methods - if RPC is not available other methods should discover it first + return false; + } + + return true; + } + + private boolean hasApplicationForm(Long voId) { + if (!this.connectorRpc.isEnabled()) { + return false; + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("vo", voId); + try { + connectorRpc.post(REGISTRAR_MANAGER, "getApplicationForm", map); + } catch (Exception e) { + // when vo does not have form exception is thrown. Every error thus is supposed as vo without form + // this method will be used after calling other RPC methods - if RPC is not available other methods should discover it first + return false; + } + + return true; + } + + private List<Group> getGroupsWhereUserIsActive(Facility facility, Long userId) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("facility", facility.getId()); + map.put("user", userId); + JsonNode jsonNode = connectorRpc.post(USERS_MANAGER, "getGroupsWhereUserIsActive", map); + + return RpcMapper.mapGroups(jsonNode); + } + + private Map<Long, Vo> convertVoListToMap(List<Vo> vos) { + if (!this.connectorRpc.isEnabled()) { + return new HashMap<>(); + } + + Map<Long, Vo> map = new HashMap<>(); + for (Vo vo : vos) { + map.put(vo.getId(), vo); + } + + return map; + } + + private List<Resource> getAssignedResources(Facility facility) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("facility", facility.getId()); + + JsonNode res = connectorRpc.post(FACILITIES_MANAGER, "getAssignedResources", map); + return RpcMapper.mapResources(res); + } + + private List<Resource> getAssignedRichResources(Facility facility) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("facility", facility.getId()); + + JsonNode res = connectorRpc.post(FACILITIES_MANAGER, "getAssignedRichResources", map); + return RpcMapper.mapResources(res); + } + + private List<Group> getRichGroupsAssignedToResourceWithAttributesByNames(Resource resource, List<String> attrNames) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + Map<String, Object> map = new LinkedHashMap<>(); + Set<AttributeMapping> mappings = this.getGroupAttributesMappingService() + .getMappingsByIdentifiers(attrNames); + List<String> rpcNames = mappings.stream().map(AttributeMapping::getRpcName).collect(Collectors.toList()); + map.put("resource", resource.getId()); + map.put("attrNames", rpcNames); + + JsonNode res = connectorRpc.post(GROUPS_MANAGER, "getRichGroupsAssignedToResourceWithAttributesByNames", map); + List<Group> groups = new ArrayList<>(); + + for (int i = 0; i < res.size(); i++) { + JsonNode jsonNode = res.get(i); + Group group = RpcMapper.mapGroup(jsonNode); + + JsonNode groupAttrs = jsonNode.get("attributes"); + Map<String, JsonNode> attrsMap = new HashMap<>(); + + for (int j = 0; j < groupAttrs.size(); j++) { + JsonNode attr = groupAttrs.get(j); + + String namespace = attr.get("namespace").textValue(); + String friendlyName = attr.get("friendlyName").textValue(); + + attrsMap.put(namespace + ":" + friendlyName, attr); + } + + group.setAttributes(attrsMap); + groups.add(group); + } + + return groups; + } + + private PerunAttribute getAttribute(PerunEntityType entity, Long entityId, String attributeName) { + if (!this.connectorRpc.isEnabled()) { + return null; + } + + AttributeMapping mapping; + switch (entity) { + case USER: mapping = this.getUserAttributesMappingService() + .getMappingByIdentifier(attributeName); + break; + case FACILITY: mapping = this.getFacilityAttributesMappingService() + .getMappingByIdentifier(attributeName); + break; + case VO: mapping = this.getVoAttributesMappingService() + .getMappingByIdentifier(attributeName); + break; + case GROUP: mapping = this.getGroupAttributesMappingService() + .getMappingByIdentifier(attributeName); + break; + case RESOURCE: mapping = this.getResourceAttributesMappingService() + .getMappingByIdentifier(attributeName); + break; + default: + throw new IllegalArgumentException("Unrecognized entity"); + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put(entity.toString().toLowerCase(), entityId); + map.put("attributeName", mapping.getRpcName()); + + JsonNode res = connectorRpc.post(ATTRIBUTES_MANAGER, "getAttribute", map); + return RpcMapper.mapAttribute(res); + } + + private List<UserExtSource> getUserExtSources(Long userId) { + if (!this.connectorRpc.isEnabled()) { + return new ArrayList<>(); + } + + Map<String, Object> map = new LinkedHashMap<>(); + map.put("user", userId); + + JsonNode response = connectorRpc.post(USERS_MANAGER, "getUserExtSources", map); + return RpcMapper.mapUserExtSources(response); + } + + private Set<String> getFacilityCapabilities(Facility facility, String capabilitiesAttrName) { + if (!this.connectorRpc.isEnabled()) { + return new HashSet<>(); + } + + Set<String> capabilities = new HashSet<>(); + if (facility != null) { + PerunAttributeValue attr = getFacilityAttributeValue(facility, capabilitiesAttrName); + if (attr != null && attr.valueAsList() != null) { + capabilities = new HashSet<>(attr.valueAsList()); + } + } + + return capabilities; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterWithMappingServices.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterWithMappingServices.java new file mode 100644 index 000000000..f6ba47d86 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/adapters/impl/PerunAdapterWithMappingServices.java @@ -0,0 +1,75 @@ +package cz.muni.ics.oidc.server.adapters.impl; + +import cz.muni.ics.oidc.server.AttributeMappingsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +/** + * Abstract class containing different mapping services. Adapter implementation should extend this class if + * the implementation needs to use the mapping service. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public abstract class PerunAdapterWithMappingServices { + + @Autowired + @Qualifier("userAttributesMappingService") + private AttributeMappingsService userAttributesMappingService; + + @Autowired + @Qualifier("facilityAttributesMappingService") + private AttributeMappingsService facilityAttributesMappingService; + + @Autowired + @Qualifier("groupAttributesMappingService") + private AttributeMappingsService groupAttributesMappingService; + + @Autowired + @Qualifier("voAttributesMappingService") + private AttributeMappingsService voAttributesMappingService; + + @Autowired + @Qualifier("resourceAttributesMappingService") + private AttributeMappingsService resourceAttributesMappingService; + + public AttributeMappingsService getUserAttributesMappingService() { + return userAttributesMappingService; + } + + public void setUserAttributesMappingService(AttributeMappingsService userAttributesMappingService) { + this.userAttributesMappingService = userAttributesMappingService; + } + + public AttributeMappingsService getFacilityAttributesMappingService() { + return facilityAttributesMappingService; + } + + public void setFacilityAttributesMappingService(AttributeMappingsService facilityAttributesMappingService) { + this.facilityAttributesMappingService = facilityAttributesMappingService; + } + + public AttributeMappingsService getGroupAttributesMappingService() { + return groupAttributesMappingService; + } + + public void setGroupAttributesMappingService(AttributeMappingsService groupAttributesMappingService) { + this.groupAttributesMappingService = groupAttributesMappingService; + } + + public AttributeMappingsService getVoAttributesMappingService() { + return voAttributesMappingService; + } + + public void setVoAttributesMappingService(AttributeMappingsService voAttributesMappingService) { + this.voAttributesMappingService = voAttributesMappingService; + } + + public AttributeMappingsService getResourceAttributesMappingService() { + return resourceAttributesMappingService; + } + + public void setResourceAttributesMappingService(AttributeMappingsService resourceAttributesMappingService) { + this.resourceAttributesMappingService = resourceAttributesMappingService; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimContextCommonParameters.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimContextCommonParameters.java new file mode 100644 index 000000000..92d1fbe06 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimContextCommonParameters.java @@ -0,0 +1,21 @@ +package cz.muni.ics.oidc.server.claims; + +import cz.muni.ics.oidc.models.Facility; + +public class ClaimContextCommonParameters { + + private Facility client; + + public ClaimContextCommonParameters(Facility client) { + this.client = client; + } + + public Facility getClient() { + return client; + } + + public void setClient(Facility client) { + this.client = client; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimModifier.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimModifier.java new file mode 100644 index 000000000..0c51e3b6e --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimModifier.java @@ -0,0 +1,47 @@ +package cz.muni.ics.oidc.server.claims; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Interface for all code that needs to modify claim values. + * + * @see cz.muni.ics.oidc.server.claims.modifiers for different implementations of claim value modifiers + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public abstract class ClaimModifier { + + private static final Logger log = LoggerFactory.getLogger(ClaimModifier.class); + + private final String claimName; + private final String modifierName; + + public ClaimModifier(ClaimModifierInitContext ctx) { + this.claimName = ctx.getClaimName(); + this.modifierName = ctx.getModifierName(); + log.debug("{} - claim modifier initialized", ctx.getClaimName()); + } + + public String getClaimName() { + return claimName; + } + + public String getModifierName() { + return modifierName; + } + + public String getUnifiedName() { + return claimName + ':' + modifierName; + } + + public abstract String modify(String value); + + @Override + public String toString() { + return this.getClass().getSimpleName() + '{' + + "claimName='" + claimName + '\'' + + ", modifierName='" + modifierName + '\'' + + '}'; + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimModifierInitContext.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimModifierInitContext.java new file mode 100644 index 000000000..aa7e9d71d --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimModifierInitContext.java @@ -0,0 +1,42 @@ +package cz.muni.ics.oidc.server.claims; + +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Context for initializing ClaimModifiers. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class ClaimModifierInitContext { + + private static final Logger log = LoggerFactory.getLogger(ClaimModifierInitContext.class); + + private final String propertyPrefix; + private final Properties properties; + private final String claimName; + private final String modifierName; + + public ClaimModifierInitContext(String propertyPrefix, Properties properties, String claimName, String modifierName) { + this.propertyPrefix = propertyPrefix; + this.properties = properties; + this.claimName = claimName; + this.modifierName = modifierName; + log.debug("{}:{} - context: property prefix for modifier configured to '{}'", + claimName, modifierName, propertyPrefix); + } + + public String getClaimName() { + return claimName; + } + + public String getModifierName() { + return modifierName; + } + + public String getProperty(String suffix, String defaultValue) { + return properties.getProperty(propertyPrefix + '.' + suffix, defaultValue); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimSource.java new file mode 100644 index 000000000..a80b0dcb4 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimSource.java @@ -0,0 +1,39 @@ +package cz.muni.ics.oidc.server.claims; + +import com.fasterxml.jackson.databind.JsonNode; +import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Interface for code that can produce claim values. + * + * @see cz.muni.ics.oidc.server.claims.sources for different implementations of claim sources + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public abstract class ClaimSource { + + private static final Logger log = LoggerFactory.getLogger(ClaimSource.class); + + private final String claimName; + + public ClaimSource(ClaimSourceInitContext ctx) { + this.claimName = ctx.getClaimName(); + log.debug("{} - claim source initialized", getClaimName()); + } + + public String getClaimName() { + return claimName; + } + + public abstract Set<String> getAttrIdentifiers(); + + public abstract JsonNode produceValue(ClaimSourceProduceContext pctx); + + @Override + public String toString() { + return this.getClass().getName(); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimSourceInitContext.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimSourceInitContext.java new file mode 100644 index 000000000..c3af8de71 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimSourceInitContext.java @@ -0,0 +1,54 @@ +package cz.muni.ics.oidc.server.claims; + +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import java.util.Properties; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Context for initializing ClaimValueSources. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class ClaimSourceInitContext { + + private static final Logger log = LoggerFactory.getLogger(ClaimSourceInitContext.class); + + private final PerunOidcConfig perunOidcConfig; + private final JWTSigningAndValidationService jwtService; + private final String propertyPrefix; + private final Properties properties; + private final String claimName; + + public ClaimSourceInitContext(PerunOidcConfig perunOidcConfig, + JWTSigningAndValidationService jwtService, + String propertyPrefix, + Properties properties, + String claimName) + { + this.perunOidcConfig = perunOidcConfig; + this.jwtService = jwtService; + this.propertyPrefix = propertyPrefix; + this.properties = properties; + this.claimName = claimName; + log.debug("{} - context: property prefix for modifier configured to '{}'", claimName, propertyPrefix); + } + + public String getClaimName() { + return claimName; + } + + public String getProperty(String suffix, String defaultValue) { + return properties.getProperty(propertyPrefix + "." + suffix, defaultValue); + } + + public JWTSigningAndValidationService getJwtService() { + return jwtService; + } + + public PerunOidcConfig getPerunOidcConfig() { + return perunOidcConfig; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimSourceProduceContext.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimSourceProduceContext.java new file mode 100644 index 000000000..f132594a2 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimSourceProduceContext.java @@ -0,0 +1,68 @@ +package cz.muni.ics.oidc.server.claims; + +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import java.util.Map; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; + +/** + * Context in which the value of the claim is produced. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class ClaimSourceProduceContext { + + private final long perunUserId; + private final String sub; + private final Map<String, PerunAttributeValue> attrValues; + private final PerunAdapter perunAdapter; + private final ClientDetailsEntity client; + private final ClaimContextCommonParameters contextCommonParameters; + + public ClaimSourceProduceContext(long perunUserId, + String sub, + Map<String, PerunAttributeValue> attrValues, + PerunAdapter perunAdapter, + ClientDetailsEntity client, + ClaimContextCommonParameters contextCommonParameters) + { + this.perunUserId = perunUserId; + this.sub = sub; + this.attrValues = attrValues; + this.perunAdapter = perunAdapter; + this.client = client; + this.contextCommonParameters = contextCommonParameters; + } + + public Map<String, PerunAttributeValue> getAttrValues() { + return attrValues; + } + + public long getPerunUserId() { + return perunUserId; + } + + public String getSub() { + return sub; + } + + public PerunAdapter getPerunAdapter() { + return perunAdapter; + } + + public ClientDetailsEntity getClient() { + return client; + } + + public ClaimContextCommonParameters getContextCommonParameters() { + return contextCommonParameters; + } + + @Override + public String toString() { + return "ClaimSourceProduceContext{" + + "perunUserId=" + perunUserId + + ", sub='" + sub + '\'' + + '}'; + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimUtils.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimUtils.java new file mode 100644 index 000000000..b24dafa18 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/ClaimUtils.java @@ -0,0 +1,38 @@ +package cz.muni.ics.oidc.server.claims; + +import org.springframework.util.StringUtils; + +public class ClaimUtils { + + public static final String NO_VALUE = null; + + public static boolean isPropSetAndHasNonNullAttribute(String propertyName, ClaimSourceProduceContext ctx) { + return isPropSetAndHasAttribute(propertyName, ctx) + && ctx.getAttrValues().get(propertyName) != null; + } + + public static boolean isPropSetAndHasAttribute(String propertyName, ClaimSourceProduceContext ctx) { + return isPropSet(propertyName) && ctx.getAttrValues().containsKey(propertyName); + } + + public static boolean isPropSet(String propertyName) { + return StringUtils.hasText(propertyName); + } + + public static String fillStringPropertyOrNoVal(String suffix, ClaimSourceInitContext ctx) { + return fillStringPropertyOrNoVal(ctx.getProperty(suffix, NO_VALUE)); + } + + public static String fillStringPropertyOrNoVal(String suffix, ClaimModifierInitContext ctx) { + return fillStringPropertyOrNoVal(ctx.getProperty(suffix, NO_VALUE)); + } + + private static String fillStringPropertyOrNoVal(String prop) { + if (StringUtils.hasText(prop)) { + return prop; + } else { + return NO_VALUE; + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/PerunCustomClaimDefinition.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/PerunCustomClaimDefinition.java new file mode 100644 index 000000000..0cdee1464 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/PerunCustomClaimDefinition.java @@ -0,0 +1,71 @@ +package cz.muni.ics.oidc.server.claims; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Keeps definition of a custom user claim. + * + * Configuration declaring custom claims: + * <ul> + * <li><b>custom.claims</b> - coma separated list of names of the claims</li> + * </ul> + * + * Configuration for claim(replace [claimName] with name of the claim): * + * <ul> + * <li><b>custom.claim.[claimName].claim</b> - name of the claim</li> + * <li><b>custom.claim.[claimName].scope</b> - scope that needs to be granted to include the claim</li> + * <li><b>custom.claim.[claimName].source.class</b> instance of a class implementing {@link ClaimSource}</li> + * <li><b>custom.claim.[claimName].modifier.class</b> instance of a class implementing {@link ClaimModifier}</li> + * </ul> + * + * + * @see ClaimSource + * @see ClaimModifier + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class PerunCustomClaimDefinition { + + private static final Logger log = LoggerFactory.getLogger(PerunCustomClaimDefinition.class); + + private final String scope; + private final String claim; + private final ClaimSource claimSource; + private final List<ClaimModifier> claimModifiers = new ArrayList<>(); + + public PerunCustomClaimDefinition(String scope, + String claim, + ClaimSource claimSource, + List<ClaimModifier> claimModifiers) { + this.scope = scope; + this.claim = claim; + this.claimSource = claimSource; + this.claimModifiers.addAll(claimModifiers); + log.debug("initialized scope '{}' with claim '{}', claimSource '{}' and modifiers '{}", scope, claim, + (claimSource != null ? claimSource.getClass().getSimpleName() : "none"), + (!claimModifiers.isEmpty() ? claimModifiers.stream() + .map(cm -> cm.getClass().getSimpleName()) + .collect(Collectors.joining(",")) : "none") + ); + } + + public String getScope() { + return scope; + } + + public String getClaim() { + return claim; + } + + public ClaimSource getClaimSource() { + return claimSource; + } + + public List<ClaimModifier> getClaimModifiers() { + return claimModifiers; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/AppendModifier.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/AppendModifier.java new file mode 100644 index 000000000..606495397 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/AppendModifier.java @@ -0,0 +1,46 @@ +package cz.muni.ics.oidc.server.claims.modifiers; + +import cz.muni.ics.oidc.server.claims.ClaimModifier; +import cz.muni.ics.oidc.server.claims.ClaimModifierInitContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Appending modifier. Appends the given text to the claim value. + * + * Configuration (replace [claimName] with the name of the claim and [modifierName] with the name of modifier): + * <ul> + * <li><b>custom.claim.[claimName].modifier.[modifierName].append</b> - string to be appended to the value</li> + * </ul> + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +@SuppressWarnings("unused") +public class AppendModifier extends ClaimModifier { + + private static final Logger log = LoggerFactory.getLogger(AppendModifier.class); + + private static final String APPEND = "append"; + + private final String appendText; + + public AppendModifier(ClaimModifierInitContext ctx) { + super(ctx); + appendText = ctx.getProperty(APPEND, ""); + log.debug("{}(modifier) - appendText: '{}'", getUnifiedName(), appendText); + } + + @Override + public String modify(String value) { + String modified = value + appendText; + log.trace("{} - modifying value '{}' by appending text '{}'", getUnifiedName(), value, appendText); + log.trace("{} - new value: '{}", getUnifiedName(), modified); + return modified; + } + + @Override + public String toString() { + return getUnifiedName() + " - AppendModifier appending " + appendText; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/GroupNamesAARCFormatModifier.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/GroupNamesAARCFormatModifier.java new file mode 100644 index 000000000..19586a106 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/GroupNamesAARCFormatModifier.java @@ -0,0 +1,64 @@ +package cz.muni.ics.oidc.server.claims.modifiers; + +import com.google.common.net.UrlEscapers; +import cz.muni.ics.oidc.server.claims.ClaimModifier; +import cz.muni.ics.oidc.server.claims.ClaimModifierInitContext; +import cz.muni.ics.oidc.server.claims.ClaimUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * GroupName to AARC Format modifier. Converts groupName values to AARC format. + * Construction: prefix:URL_ENCODED_VALUE#authority + * Example: urn:geant:cesnet.cz:group:some%20value#perun.cesnet.cz + * + * Configuration (replace [claimName] with the name of the claim and [modifierName] with the name of modifier): + * <ul> + * <li><b>custom.claim.[claimName].modifier.[modifierName].prefix</b> - string to be prepended to the value, + * defaults to <i>urn:geant:cesnet.cz:group:</i> + * </li> + * <li><b>custom.claim.[claimName].modifier.[modifierName].authority</b> - string to be appended to the value, + * represents authority who has released the value, defaults to <i>perun.cesnet.cz</i> + * </li> + * </ul> + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +@SuppressWarnings("unused") +public class GroupNamesAARCFormatModifier extends ClaimModifier { + + private static final Logger log = LoggerFactory.getLogger(GroupNamesAARCFormatModifier.class); + + public static final String PREFIX = "prefix"; + public static final String AUTHORITY = "authority"; + + private final String prefix; + private final String authority; + + public GroupNamesAARCFormatModifier(ClaimModifierInitContext ctx) { + super(ctx); + this.prefix = ClaimUtils.fillStringPropertyOrNoVal(PREFIX, ctx); + if (!ClaimUtils.isPropSet(this.prefix)) { + throw new IllegalArgumentException(getUnifiedName() + " - missing mandatory configuration option: " + PREFIX); + } + this.authority = ClaimUtils.fillStringPropertyOrNoVal(AUTHORITY, ctx); + if (!ClaimUtils.isPropSet(this.authority)) { + throw new IllegalArgumentException(getUnifiedName() + " - missing mandatory configuration option: " + AUTHORITY); + } + log.debug("{}:{}(modifier) - prefix: '{}', authority: '{}'", getClaimName(), getModifierName(), prefix, authority); + } + + @Override + public String modify(String value) { + String modified = prefix + UrlEscapers.urlPathSegmentEscaper().escape(value) + "#" + authority; + log.trace("{} - modifying value '{}' to AARC format", getUnifiedName(), value); + log.trace("{} - new value: '{}", getUnifiedName(), modified); + return modified; + } + + @Override + public String toString() { + return getUnifiedName() + " - GroupNamesAARCFormatModifier to " + prefix + "<GROUP>#" + authority; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/NoOperationModifier.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/NoOperationModifier.java new file mode 100644 index 000000000..6578de050 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/NoOperationModifier.java @@ -0,0 +1,30 @@ +package cz.muni.ics.oidc.server.claims.modifiers; + +import cz.muni.ics.oidc.server.claims.ClaimModifier; +import cz.muni.ics.oidc.server.claims.ClaimModifierInitContext; + +/** + * No operation modifier. Class just for consistent working with modifiers to avoid checking for null references. + * + * No further configuration. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@SuppressWarnings("unused") +public class NoOperationModifier extends ClaimModifier { + + public NoOperationModifier(ClaimModifierInitContext ctx) { + super(ctx); + } + + @Override + public String modify(String value) { + return value; + } + + @Override + public String toString() { + return getUnifiedName() + " - No operation modifier"; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/RegexReplaceModifier.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/RegexReplaceModifier.java new file mode 100644 index 000000000..089186d9c --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/modifiers/RegexReplaceModifier.java @@ -0,0 +1,53 @@ +package cz.muni.ics.oidc.server.claims.modifiers; + +import cz.muni.ics.oidc.server.claims.ClaimModifier; +import cz.muni.ics.oidc.server.claims.ClaimModifierInitContext; +import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Replace regex modifier. Replaces parts matched by regex with string using backreferences to groups. + * + * Configuration (replace [claimName] with the name of the claim and [modifierName] with the name of modifier): + * <ul> + * <li><b>custom.claim.[claimName].modifier.[modifierName].find</b> - string to be replaced, can be a regex</li> + * <li><b>custom.claim.[claimName].modifier.[modifierName].replace</b> - string to be used as replacement</li> + * </ul> + * + * @see java.util.regex.Matcher#replaceAll(String) + * @author Martin Kuba <makub@ics.muni.cz> + */ +@SuppressWarnings("unused") +public class RegexReplaceModifier extends ClaimModifier { + + private static final Logger log = LoggerFactory.getLogger(RegexReplaceModifier.class); + + private static final String FIND = "find"; + private static final String REPLACE = "replace"; + + private final Pattern regex; + private final String replacement; + + public RegexReplaceModifier(ClaimModifierInitContext ctx) { + super(ctx); + regex = Pattern.compile(ctx.getProperty(FIND, "")); + replacement = ctx.getProperty(REPLACE, ""); + log.debug("{}(modifier) - regex: '{}', replacement: '{}'", getUnifiedName(), regex, replacement); + } + + @Override + public String modify(String value) { + String modified = regex.matcher(value).replaceAll(replacement); + log.trace("{} - modifying value '{}' by replacing matched part ('{}') with: '{}'", getUnifiedName(), + value, regex, replacement); + log.trace("{} - new value: '{}", getUnifiedName(), modified); + return modified; + } + + @Override + public String toString() { + return getUnifiedName() + " - RegexReplaceModifier replacing '" + regex.pattern() + + "' with '" + replacement + '\''; + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/EdupersonScopedAffiliationsMUSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/EdupersonScopedAffiliationsMUSource.java new file mode 100644 index 000000000..e0ea37466 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/EdupersonScopedAffiliationsMUSource.java @@ -0,0 +1,112 @@ +package cz.muni.ics.oidc.server.claims.sources; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; +import cz.muni.ics.oidc.server.claims.ClaimSource; +import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Claim source for eduperson_scoped_affiliations MUNI. + * + * Configuration (replace [claimName] with the name of the claim): + * <ul> + * <li> + * <b>custom.claim.[claimName].source.config_file</b> - path to the YML config file, see + * 'eduperson_scoped_affiliations_mu_source.yml' for example configuration + * </li> + * </ul> + * + * @author Dominik Baránek <baranek@ics.muni.cz> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class EdupersonScopedAffiliationsMUSource extends ClaimSource { + + private static final Logger log = LoggerFactory.getLogger(EdupersonScopedAffiliationsMUSource.class); + + private static final String CONFIG_FILE = "config_file"; + private static final String KEY_SCOPE = "scope"; + private static final String KEY_VO_ID = "voId"; + private static final String KEY_AFFILIATIONS = "affiliations"; + private static final String KEY_VALUE = "value"; + private static final String KEY_GROUPS = "groups"; + + private static final String DEFAULT_PATH = "/etc/perun/eduperson_scoped_affiliations_mu_source.yml"; + + private final Map<List<Long>, String> affiliations = new HashMap<>(); + private Long voId = 363L; + private String valueScope = "muni.cz"; + + public EdupersonScopedAffiliationsMUSource(ClaimSourceInitContext ctx) { + super(ctx); + parseConfigFile(ctx.getProperty(CONFIG_FILE, DEFAULT_PATH)); + log.debug("{} - affiliations: '{}', voId: '{}', valueScope: '{}'", + getClaimName(), affiliations, voId, valueScope); + } + + @Override + public Set<String> getAttrIdentifiers() { + return Collections.emptySet(); + } + + @Override + public JsonNode produceValue(ClaimSourceProduceContext pctx) { + Long userId = pctx.getPerunUserId(); + ArrayNode result = JsonNodeFactory.instance.arrayNode(); + Set<Long> groups = pctx.getPerunAdapter().getUserGroupsIds(userId, voId); + for (Map.Entry<List<Long>, String> entry : affiliations.entrySet()) { + for (Long id: entry.getKey()) { + if (groups.contains(id)) { + String affiliation = entry.getValue() + '@' + valueScope; + log.trace("{} - added affiliation '{}' due to membership in group '{}'", + getClaimName(), affiliation, id); + result.add(affiliation); + break; + } + } + } + + if (result.size() == 0) { + String affiliation = "affiliate@" + valueScope; + log.trace("{} - user is not a member in any special groups, added default affiliation: '{}'", + getClaimName(), affiliation); + result.add(affiliation); + } + + log.debug("{} - produced value for user({}): '{}'", getClaimName(), userId, result); + return result; + } + + private void parseConfigFile(String file) { + log.trace("{} - Loading config file {}", getClaimName(), file); + YAMLMapper mapper = new YAMLMapper(); + try { + JsonNode root = mapper.readValue(new File(file), JsonNode.class); + valueScope = root.get(KEY_SCOPE).asText(); + voId = root.get(KEY_VO_ID).longValue(); + for (JsonNode affiliationMapping : root.path(KEY_AFFILIATIONS)) { + String value = affiliationMapping.path(KEY_VALUE).asText(); + List<Long> gids = new ArrayList<>(); + for (JsonNode gid : affiliationMapping.path(KEY_GROUPS)) { + gids.add(gid.asLong()); + } + affiliations.put(gids, value); + } + } catch (IOException ex) { + log.warn("{} - cannot read claim configuration file: '{}'", getClaimName(), file); + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/EntitlementExtendedClaimSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/EntitlementExtendedClaimSource.java new file mode 100644 index 000000000..4c1017bad --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/EntitlementExtendedClaimSource.java @@ -0,0 +1,82 @@ +package cz.muni.ics.oidc.server.claims.sources; + +import com.fasterxml.jackson.databind.JsonNode; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.Group; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; +import org.yaml.snakeyaml.external.com.google.gdata.util.common.base.PercentEscaper; + +public class EntitlementExtendedClaimSource extends EntitlementSource { + + public static final Logger log = LoggerFactory.getLogger(EntitlementExtendedClaimSource.class); + + private static final String GROUP = "group"; + private static final String GROUP_ATTRIBUTES = "groupAttributes"; + private static final String DISPLAY_NAME = "displayName"; + + private static final PercentEscaper ESCAPER = new PercentEscaper("-_.!~*'()", false); + + public EntitlementExtendedClaimSource(ClaimSourceInitContext ctx) { + super(ctx); + log.debug("{} - initialized", getClaimName()); + } + + @Override + public Set<String> getAttrIdentifiers() { + return super.getAttrIdentifiers(); + } + + @Override + public JsonNode produceValue(ClaimSourceProduceContext pctx) { + Long userId = pctx.getPerunUserId(); + Set<String> entitlements = produceEntitlementsExtended(pctx.getContextCommonParameters().getClient(), + userId, pctx.getPerunAdapter()); + JsonNode result = convertResultStringsToJsonArray(entitlements); + log.debug("{} - produced value for user({}): '{}'", getClaimName(), userId, result); + return result; + } + + private Set<String> produceEntitlementsExtended(Facility facility, Long userId, PerunAdapter perunAdapter) { + Set<Group> userGroups = getUserGroupsOnFacility(facility, userId, perunAdapter); + Map<Long, String> groupIdToNameMap = super.getGroupIdToNameMap(userGroups, false); + Set<String> entitlements = new TreeSet<>(); + this.fillUuidEntitlements(userGroups, entitlements); + fillForwardedEntitlements(perunAdapter, userId, entitlements); + fillCapabilities(facility, perunAdapter, groupIdToNameMap,entitlements); + log.trace("{} - UUID entitlements added", getClaimName()); + return entitlements; + } + + private void fillUuidEntitlements(Set<Group> userGroups, Set<String> entitlements) { + for (Group group : userGroups) { + String displayName = group.getUniqueGroupName(); + if (StringUtils.hasText(displayName) && MEMBERS.equals(group.getName())) { + displayName = displayName.replace(':' + MEMBERS, ""); + } + String entitlement = wrapGroupEntitlementToAARC(group.getUuid()); + log.trace("{} - added UUID entitlement: '{}'", getClaimName(), entitlement); + entitlements.add(entitlement); + String entitlementWithAttributes = wrapGroupEntitlementToAARCWithAttributes(group.getUuid(), displayName); + log.trace("{} - added UUID entitlement with displayName: '{}'", getClaimName(), entitlementWithAttributes); + entitlements.add(entitlementWithAttributes); + } + } + + private String wrapGroupEntitlementToAARC(String uuid) { + return addPrefixAndSuffix(GROUP + ':' + uuid); + } + + private String wrapGroupEntitlementToAARCWithAttributes(String uuid, String displayName) { + return addPrefixAndSuffix(GROUP_ATTRIBUTES + ':' + uuid + "?=" + DISPLAY_NAME + '=' + + ESCAPER.escape(displayName)); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/EntitlementSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/EntitlementSource.java new file mode 100644 index 000000000..2e8432b1c --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/EntitlementSource.java @@ -0,0 +1,185 @@ +package cz.muni.ics.oidc.server.claims.sources; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.net.UrlEscapers; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.Group; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext; +import cz.muni.ics.oidc.server.claims.ClaimUtils; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +/** + * This source converts groupNames and resource capabilities to AARC format and joins them with eduPersonEntitlement. + * + * Configuration (replace [claimName] with the name of the claim): + * <ul> + * <li> + * <b>custom.claim.[claimName].source.forwardedEntitlements</b> - forwardedEntitlements attribute name, + * if not specified, the forwarded entitlements will not be added to the list + * </li> + * <li><b>custom.claim.[claimName].source.resourceCapabilities</b> - resource capabilities attribute name for resources</li> + * <li><b>custom.claim.[claimName].source.facilityCapabilities</b> - resource capabilities attribute name for facility</li> + * <li><b>custom.claim.[claimName].source.prefix</b> - string to be prepended to the value,</li> + * <li> + * <b>custom.claim.[claimName].source.authority</b> - string to be appended to the value, represents authority + * who has released the value + * </li> + * </ul> + * + * @author Dominik Baránek <baranek@ics.muni.cz> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class EntitlementSource extends GroupNamesSource { + + public static final Logger log = LoggerFactory.getLogger(EntitlementSource.class); + + private static final String GROUP = "group"; + + protected static final String FORWARDED_ENTITLEMENTS = "forwardedEntitlements"; + protected static final String RESOURCE_CAPABILITIES = "resourceCapabilities"; + protected static final String FACILITY_CAPABILITIES = "facilityCapabilities"; + protected static final String PREFIX = "prefix"; + protected static final String AUTHORITY = "authority"; + + private final String forwardedEntitlements; + private final String resourceCapabilities; + private final String facilityCapabilities; + private final String prefix; + private final String authority; + + public EntitlementSource(ClaimSourceInitContext ctx) { + super(ctx); + this.forwardedEntitlements = ClaimUtils.fillStringPropertyOrNoVal(FORWARDED_ENTITLEMENTS, ctx); + this.resourceCapabilities = ClaimUtils.fillStringPropertyOrNoVal(RESOURCE_CAPABILITIES, ctx); + this.facilityCapabilities = ClaimUtils.fillStringPropertyOrNoVal(FACILITY_CAPABILITIES, ctx); + this.prefix = ClaimUtils.fillStringPropertyOrNoVal(PREFIX, ctx); + if (!ClaimUtils.isPropSet(this.prefix)) { + throw new IllegalArgumentException(getClaimName() + " - missing mandatory configuration option: " + + PREFIX); + } + this.authority = ClaimUtils.fillStringPropertyOrNoVal(AUTHORITY, ctx); + if (!ClaimUtils.isPropSet(this.authority)) { + throw new IllegalArgumentException(getClaimName() + " - missing mandatory configuration option: " + + AUTHORITY); + } + log.debug("{} - forwardedEntitlements: '{}', resourceCapabilities: '{}', facilityCapabilities: '{}', " + + "prefix: '{}', authority: '{}'", getClaimName(), forwardedEntitlements, resourceCapabilities, + facilityCapabilities, prefix, authority); + } + + @Override + public Set<String> getAttrIdentifiers() { + Set<String> set = new HashSet<>(super.getAttrIdentifiers()); + if (forwardedEntitlements != null) { + set.add(forwardedEntitlements); + } + return set; + } + + @Override + public JsonNode produceValue(ClaimSourceProduceContext pctx) { + PerunAdapter perunAdapter = pctx.getPerunAdapter(); + Long userId = pctx.getPerunUserId(); + Facility facility = pctx.getContextCommonParameters().getClient(); + Set<Group> userGroups = getUserGroupsOnFacility(facility, userId, perunAdapter); + Set<String> entitlements = produceEntitlements(facility, userGroups, userId, perunAdapter); + + JsonNode result = convertResultStringsToJsonArray(entitlements); + log.debug("{} - produced value for user({}): '{}'", getClaimName(), userId, result); + return result; + } + + protected void fillCapabilities(Facility facility, PerunAdapter perunAdapter, + Map<Long, String> idToGnameMap, Set<String> entitlements) { + Set<String> resultCapabilities = perunAdapter + .getCapabilities(facility, idToGnameMap, + ClaimUtils.isPropSet(this.facilityCapabilities) ? facilityCapabilities : null, + ClaimUtils.isPropSet(this.resourceCapabilities)? resourceCapabilities: null); + + for (String capability : resultCapabilities) { + entitlements.add(wrapCapabilityToAARC(capability)); + log.trace("{} - added capability: {}", getClaimName(), capability); + } + } + + protected void fillForwardedEntitlements(PerunAdapter perunAdapter, Long userId, Set<String> entitlements) { + PerunAttributeValue forwardedEntitlementsVal = perunAdapter + .getUserAttributeValue(userId, this.forwardedEntitlements); + if (forwardedEntitlementsVal != null && !forwardedEntitlementsVal.isNullValue()) { + JsonNode eduPersonEntitlementJson = forwardedEntitlementsVal.valueAsJson(); + for (int i = 0; i < eduPersonEntitlementJson.size(); i++) { + String entitlement = eduPersonEntitlementJson.get(i).asText(); + log.trace("{} - added forwarded entitlement: {}", getClaimName(), entitlement); + entitlements.add(entitlement); + } + } + } + + private void fillEntitlementsFromGroupNames(Collection<String> groupNames, Set<String> entitlements) { + for (String fullGname: groupNames) { + if (fullGname == null || fullGname.trim().isEmpty()) { + continue; + } + + String[] parts = fullGname.split(":", 2); + if (parts.length == 2 && StringUtils.hasText(parts[1]) && MEMBERS.equals(parts[1])) { + parts[1] = parts[1].replace(MEMBERS, ""); + } + + String gname = parts[0]; + if (StringUtils.hasText(parts[1])) { + gname += (':' + parts[1]); + } + String gNameEntitlement = wrapGroupNameToAARC(gname); + log.trace("{} - added group name entitlement: {}", getClaimName(), gNameEntitlement); + entitlements.add(gNameEntitlement); + } + } + + protected Set<String> produceEntitlements(Facility facility, Set<Group> userGroups, + Long userId, PerunAdapter perunAdapter) + { + Set<String> entitlements = new TreeSet<>(); + Map<Long, String> groupIdToNameMap = super.getGroupIdToNameMap(userGroups, false); + + if (groupIdToNameMap != null && !groupIdToNameMap.values().isEmpty()) { + this.fillEntitlementsFromGroupNames(new HashSet<>(groupIdToNameMap.values()), entitlements); + log.trace("{} - entitlements for group names added", getClaimName()); + } + + if (facility != null) { + this.fillCapabilities(facility, perunAdapter, groupIdToNameMap, entitlements); + log.trace("{} - capabilities added", getClaimName()); + } + + if (ClaimUtils.isPropSet(this.forwardedEntitlements)) { + this.fillForwardedEntitlements(perunAdapter, userId, entitlements); + log.trace("{} - forwarded entitlements added", getClaimName()); + } + + return entitlements; + } + + protected String wrapGroupNameToAARC(String groupName) { + return addPrefixAndSuffix(GROUP + ':' + UrlEscapers.urlPathSegmentEscaper().escape(groupName)); + } + + private String wrapCapabilityToAARC(String capability) { + return addPrefixAndSuffix(UrlEscapers.urlPathSegmentEscaper().escape(capability)); + } + + protected String addPrefixAndSuffix(String capability) { + return prefix + capability + '#' + authority; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/ExtractValuesByDomainSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/ExtractValuesByDomainSource.java new file mode 100644 index 000000000..4ffc3b38f --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/ExtractValuesByDomainSource.java @@ -0,0 +1,99 @@ +package cz.muni.ics.oidc.server.claims.sources; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.NullNode; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.server.claims.ClaimSource; +import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext; +import cz.muni.ics.oidc.server.claims.ClaimUtils; +import java.util.Collections; +import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This source extract attribute values for given scope + * + * Configuration (replace [claimName] with the name of the claim): + * <ul> + * <li><b>custom.claim.[claimName].source.extractByDomain</b> - domain which should be matched</li> + * <li><b>custom.claim.[claimName].source.attributeName</b> - attribute in which the lookup should be performed</li> + * </ul> + * + * @author Dominik Baránek <baranek@ics.muni.cz> + */ +public class ExtractValuesByDomainSource extends ClaimSource { + + private static final Logger log = LoggerFactory.getLogger(ExtractValuesByDomainSource.class); + + private static final String EXTRACT_BY_DOMAIN = "extractByDomain"; + private static final String ATTRIBUTE_NAME = "attributeName"; + + private final String domain; + private final String attributeName; + + public ExtractValuesByDomainSource(ClaimSourceInitContext ctx) { + super(ctx); + this.domain = ClaimUtils.fillStringPropertyOrNoVal(EXTRACT_BY_DOMAIN, ctx); + if (!ClaimUtils.isPropSet(this.domain)) { + throw new IllegalArgumentException(getClaimName() + " - missing mandatory configuration option: " + + EXTRACT_BY_DOMAIN); + } + this.attributeName = ClaimUtils.fillStringPropertyOrNoVal(ATTRIBUTE_NAME, ctx); + if (!ClaimUtils.isPropSet(this.attributeName)) { + throw new IllegalArgumentException(getClaimName() + " - missing mandatory configuration option: " + + ATTRIBUTE_NAME); + } + log.debug("{} - domain: '{}', attributeName: '{}'", getClaimName(), domain, attributeName); + } + + @Override + public Set<String> getAttrIdentifiers() { + return Collections.singleton(attributeName); + } + + @Override + public JsonNode produceValue(ClaimSourceProduceContext pctx) { + JsonNode result = NullNode.getInstance(); + if (!ClaimUtils.isPropSet(domain)) { + log.trace("{} - no domain set, return empty JSON", domain); + result = NullNode.getInstance(); + } else if (!ClaimUtils.isPropSetAndHasAttribute(attributeName, pctx)) { + log.trace("{} - no attributeName set, return empty JSON", domain); + result = NullNode.getInstance(); + } else { + PerunAttributeValue attributeValue = pctx.getAttrValues().get(attributeName); + if (attributeValue != null) { + JsonNode attributeValueJson = attributeValue.valueAsJson(); + if (attributeValueJson.isTextual() && hasDomain(attributeValueJson.textValue(), domain)) { + log.trace("{} - found domain in string value: '{}'", getClaimName(), attributeValueJson); + result = attributeValueJson; + } else if (attributeValueJson.isArray()) { + ArrayNode arrayNode = (ArrayNode) attributeValueJson; + JsonNodeFactory factory = JsonNodeFactory.instance; + ArrayNode arr = new ArrayNode(factory); + + for (int i = 0; i < arrayNode.size(); i++) { + String subValue = arrayNode.get(i).textValue(); + if (hasDomain(subValue, domain)) { + log.trace("{} - found domain in array sub-value: '{}'", getClaimName(), subValue); + arr.add(subValue); + } + } + result = arr; + } + } + } + log.debug("{} - produced value for user({}): '{}'", getClaimName(), pctx.getPerunUserId(), result); + return result; + } + + private boolean hasDomain(String value, String domain) { + String[] parts = value.split("@"); + return parts[parts.length - 1].equals(domain); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/GroupNamesSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/GroupNamesSource.java new file mode 100644 index 000000000..fe090bb2c --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/GroupNamesSource.java @@ -0,0 +1,92 @@ +package cz.muni.ics.oidc.server.claims.sources; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.Group; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.claims.ClaimSource; +import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +/** + * Source fetches all unique group names in context of user and facility. If no facility exists for the client, empty + * list is returned as result. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class GroupNamesSource extends ClaimSource { + + public static final Logger log = LoggerFactory.getLogger(GroupNamesSource.class); + + protected static final String MEMBERS = "members"; + + public GroupNamesSource(ClaimSourceInitContext ctx) { + super(ctx); + log.debug("{} - initialized", getClaimName()); + } + + @Override + public Set<String> getAttrIdentifiers() { + return Collections.emptySet(); + } + + @Override + public JsonNode produceValue(ClaimSourceProduceContext pctx) { + Map<Long, String> idToNameMap = this.produceGroupNames(pctx); + JsonNode result = convertResultStringsToJsonArray(new HashSet<>(idToNameMap.values())); + log.debug("{} - produced value for user({}): '{}'", getClaimName(), pctx.getPerunUserId(), result); + return result; + } + + protected Map<Long, String> produceGroupNames(ClaimSourceProduceContext pctx) { + log.trace("{} - produce group names with trimming 'members' part of the group names", getClaimName()); + Facility facility = pctx.getContextCommonParameters().getClient(); + Set<Group> userGroups = getUserGroupsOnFacility(facility, pctx.getPerunUserId(), pctx.getPerunAdapter()); + return getGroupIdToNameMap(userGroups, true); + } + + protected Map<Long, String> getGroupIdToNameMap(Set<Group> userGroups, boolean trimMembers) { + Map<Long, String> idToNameMap = new HashMap<>(); + userGroups.forEach(g -> { + String uniqueName = g.getUniqueGroupName(); + if (trimMembers && StringUtils.hasText(uniqueName) && MEMBERS.equals(g.getName())) { + uniqueName = uniqueName.replace(':' + MEMBERS, ""); + g.setUniqueGroupName(uniqueName); + } + + idToNameMap.put(g.getId(), g.getUniqueGroupName()); + }); + + log.trace("{} - group ID to group name map: '{}'", getClaimName(), idToNameMap); + return idToNameMap; + } + + protected Set<Group> getUserGroupsOnFacility(Facility facility, Long userId, PerunAdapter perunAdapter) { + Set<Group> userGroups = new HashSet<>(); + if (facility == null) { + log.warn("{} - no facility provided when searching for user groups, will return empty set", getClaimName()); + } else { + userGroups = perunAdapter.getGroupsWhereUserIsActiveWithUniqueNames(facility.getId(), userId); + } + log.trace("{} - found user groups: '{}'", getClaimName(), userGroups); + return userGroups; + } + + protected JsonNode convertResultStringsToJsonArray(Collection<String> collection) { + ArrayNode arr = JsonNodeFactory.instance.arrayNode(); + collection.forEach(arr::add); + return arr; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/IsCesnetEligibleClaimSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/IsCesnetEligibleClaimSource.java new file mode 100644 index 000000000..0992bced4 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/IsCesnetEligibleClaimSource.java @@ -0,0 +1,100 @@ +package cz.muni.ics.oidc.server.claims.sources; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import cz.muni.ics.oidc.server.claims.ClaimSource; +import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext; +import cz.muni.ics.oidc.server.claims.ClaimUtils; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Collections; +import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +/** + * This source checks if the timestamp is within 12 months from now. If so, returns TRUE, FALSE otherwise. + * + * Configuration (replace [claimName] with the name of the claim): + * <ul> + * <li><b>custom.claim.[claimName].source.attribute</b> - attribute containing the isCesnetEligible timestamp</li> + * <li><b>custom.claim.[claimName].source.valueFormat</b> - format of the value (i.e. yyyy-MM-dd HH:mm:ss</li> + * </ul> + * + * @author Pavol Pluta <pavol.pluta1@gmail.com> + */ +public class IsCesnetEligibleClaimSource extends ClaimSource { + + public static final Logger log = LoggerFactory.getLogger(IsCesnetEligibleClaimSource.class); + + private static final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss"; + private static final int VALIDITY_PERIOD = 12; // 12 months + + private static final String SOURCE_ATTR_NAME = "attribute"; + private static final String VALUE_FORMAT = "valueFormat"; + + private final String sourceAttr; + private String valueFormat; + + public IsCesnetEligibleClaimSource(ClaimSourceInitContext ctx) { + super(ctx); + this.sourceAttr = ClaimUtils.fillStringPropertyOrNoVal(SOURCE_ATTR_NAME, ctx); + if (!ClaimUtils.isPropSet(sourceAttr)) { + throw new IllegalArgumentException(getClaimName() + " - missing mandatory configuration option: " + + SOURCE_ATTR_NAME); + } + this.valueFormat = ClaimUtils.fillStringPropertyOrNoVal(VALUE_FORMAT, ctx); + if (!ClaimUtils.isPropSet(valueFormat)) { + this.valueFormat = DEFAULT_FORMAT; + } + log.debug("{} - sourceAttr: '{}', valueFormat: '{}'", getClaimName(), sourceAttr, valueFormat); + } + + @Override + public Set<String> getAttrIdentifiers() { + return Collections.singleton(sourceAttr); + } + + @Override + public JsonNode produceValue(ClaimSourceProduceContext pctx) { + JsonNode result; + if (ClaimUtils.isPropSetAndHasAttribute(sourceAttr, pctx)) { + String lastSeen = pctx.getAttrValues().get(sourceAttr).valueAsString(); + result = JsonNodeFactory.instance.booleanNode(this.isCesnetEligible(lastSeen)); + } else { + result = JsonNodeFactory.instance.booleanNode(false); + } + log.debug("{} - produced value for user({}): '{}'", getClaimName(), pctx.getPerunUserId(), result); + return result; + } + + private boolean isCesnetEligible(String attrValue) { + if (!StringUtils.hasText(attrValue)) { + return false; + } + LocalDate timeStampLastSeen; + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(valueFormat); + timeStampLastSeen = LocalDate.parse(attrValue, formatter); + } catch (DateTimeParseException e) { + log.warn("{} - could not parse timestamp (for format: {}) value: '{}'", getClaimName(), valueFormat, attrValue); + return false; + } + + LocalDate now = LocalDateTime.now().toLocalDate(); + if (timeStampLastSeen.isBefore(now.minusMonths(VALIDITY_PERIOD))) { + log.trace("{} - timestamp '{}' is after the defined period of '{} months'", + getClaimName(), timeStampLastSeen, VALIDITY_PERIOD); + return false; + } else { + log.trace("{} - timestamp '{}' is within the defined period of '{} months'", + getClaimName(), timeStampLastSeen, VALIDITY_PERIOD); + return true; + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/PerunAttributeClaimSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/PerunAttributeClaimSource.java new file mode 100644 index 000000000..ef5b7d59c --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/PerunAttributeClaimSource.java @@ -0,0 +1,64 @@ +package cz.muni.ics.oidc.server.claims.sources; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.NullNode; +import cz.muni.ics.oidc.server.claims.ClaimSource; +import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext; +import cz.muni.ics.oidc.server.claims.ClaimUtils; +import java.util.Collections; +import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Source for claim which get value of attribute from Perun. + * + * Configuration (replace [claimName] with the name of the claim): + * <ul> + * <li><b>custom.claim.[claimName].source.attribute</b> - name of the attribute in Perun</li> + * </ul> + * + * @author Martin Kuba <makub@ics.muni.cz> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@SuppressWarnings("unused") +public class PerunAttributeClaimSource extends ClaimSource { + + public static final Logger log = LoggerFactory.getLogger(PerunAttributeClaimSource.class); + + private static final String ATTRIBUTE = "attribute"; + + private final String attributeName; + + public PerunAttributeClaimSource(ClaimSourceInitContext ctx) { + super(ctx); + this.attributeName = ClaimUtils.fillStringPropertyOrNoVal(ATTRIBUTE, ctx); + if (!ClaimUtils.isPropSet(this.attributeName)) { + throw new IllegalArgumentException("Missing mandatory configuration option - " + ATTRIBUTE); + } + log.debug("{} - attributeName: '{}'", getClaimName(), attributeName); + } + + @Override + public Set<String> getAttrIdentifiers() { + return Collections.singleton(attributeName); + } + + @Override + public JsonNode produceValue(ClaimSourceProduceContext pctx) { + JsonNode value = NullNode.getInstance(); + if (ClaimUtils.isPropSetAndHasAttribute(attributeName, pctx)) { + value = pctx.getAttrValues().get(attributeName).valueAsJson(); + } + + log.debug("{} - produced value for user({}): '{}'", getClaimName(), pctx.getPerunUserId(), value); + return value; + } + + @Override + public String toString() { + return "Perun attribute " + attributeName; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/StaticValueClaimSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/StaticValueClaimSource.java new file mode 100644 index 000000000..59e88d140 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/StaticValueClaimSource.java @@ -0,0 +1,87 @@ +package cz.muni.ics.oidc.server.claims.sources; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.NullNode; +import cz.muni.ics.oidc.server.claims.ClaimSource; +import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +/** + * Source for claim which releases the defined value. + * + * Configuration (replace [claimName] with the name of the claim): + * <ul> + * <li><b>custom.claim.[claimName].source.valueSeparator</b> - @NULL or actual separator, if set to smth. else than null, + * value is considered as an array</li> + * <li><b>custom.claim.[claimName].source.value</b> - list of values separated by specified separator, in case + * of string separator should be set to @NULL and full value will be released as string</li> + * </ul> + * + * @author Martin Kuba <makub@ics.muni.cz> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@SuppressWarnings("unused") +public class StaticValueClaimSource extends ClaimSource { + + public static final Logger log = LoggerFactory.getLogger(StaticValueClaimSource.class); + + private static final String NO_SEPARATOR = "@NULL"; + private static final String VALUE_SEPARATOR = "valueSeparator"; + private static final String VALUE = "value"; + + private final String valueSeparator; + private String[] valueArr; + private final String valueStr; + + public StaticValueClaimSource(ClaimSourceInitContext ctx) { + super(ctx); + this.valueSeparator = ctx.getProperty(VALUE_SEPARATOR, NO_SEPARATOR); + this.valueStr = ctx.getProperty(VALUE, null); + this.valueArr = null; + if (valueStr != null) { + valueArr = valueStr.split(valueSeparator); + } + log.debug("{} - valueSeparator: '{}', valueStr: '{}', valueArr: '{}'", getClaimName(), + valueSeparator, valueStr, valueArr); + } + + @Override + public Set<String> getAttrIdentifiers() { + return Collections.emptySet(); + } + + @Override + public JsonNode produceValue(ClaimSourceProduceContext pctx) { + JsonNode value = NullNode.getInstance(); + if (!NO_SEPARATOR.equals(valueSeparator) && valueArr != null) { + ArrayNode arrJson = JsonNodeFactory.instance.arrayNode(); + for (String v: valueArr) { + if (StringUtils.hasText(v)) { + arrJson.add(v); + } + } + if (arrJson.size() > 0) { + value = arrJson; + } + } else if (StringUtils.hasText(valueStr)) { + value = JsonNodeFactory.instance.textNode(valueStr); + } + + log.debug("{} - produced value for user({}): '{}'", getClaimName(), pctx.getPerunUserId(), value); + return value; + } + + @Override + public String toString() { + return "Fixed value " + (valueArr != null ? Arrays.toString(valueArr) : valueStr); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/TwoArrayAttributesClaimSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/TwoArrayAttributesClaimSource.java new file mode 100644 index 000000000..8f6c279b3 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/claims/sources/TwoArrayAttributesClaimSource.java @@ -0,0 +1,90 @@ +package cz.muni.ics.oidc.server.claims.sources; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import cz.muni.ics.oidc.server.claims.ClaimSource; +import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext; +import cz.muni.ics.oidc.server.claims.ClaimUtils; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Claim source which takes value from two attributes from Perun. + * + * Configuration (replace [claimName] with the name of the claim): + * <ul> + * <li><b>custom.claim.[claimName].source.attribute1</b> - name of the first attribute in Perun</li> + * <li><b>custom.claim.[claimName].source.attribute2</b> - name of the second attribute in Perun</li> + * </ul> + * + * @author Martin Kuba <makub@ics.muni.cz> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@SuppressWarnings("unused") +public class TwoArrayAttributesClaimSource extends ClaimSource { + + private static final Logger log = LoggerFactory.getLogger(TwoArrayAttributesClaimSource.class); + + public static final String ATTRIBUTE_1 = "attribute1"; + public static final String ATTRIBUTE_2 = "attribute2"; + + private final String attribute1Name; + private final String attribute2Name; + + public TwoArrayAttributesClaimSource(ClaimSourceInitContext ctx) { + super(ctx); + this.attribute1Name = ClaimUtils.fillStringPropertyOrNoVal(ATTRIBUTE_1, ctx); + if (!ClaimUtils.isPropSet(this.attribute1Name)) { + throw new IllegalArgumentException(getClaimName() + " - missing mandatory configuration option: " + + ATTRIBUTE_1); + } + this.attribute2Name = ClaimUtils.fillStringPropertyOrNoVal(ATTRIBUTE_2, ctx); + if (!ClaimUtils.isPropSet(this.attribute2Name)) { + throw new IllegalArgumentException(getClaimName() + " - missing mandatory configuration option: " + + ATTRIBUTE_2); + } + log.debug("{} - attribute1Name: '{}', attribute2Name: '{}'", getClaimName(), attribute1Name, attribute2Name); + } + + @Override + public Set<String> getAttrIdentifiers() { + return new HashSet<>(Arrays.asList(attribute1Name, attribute1Name)); + } + + @Override + public JsonNode produceValue(ClaimSourceProduceContext pctx) { + JsonNode j1 = new ArrayNode(JsonNodeFactory.instance); + if (ClaimUtils.isPropSetAndHasAttribute(attribute1Name, pctx)) { + j1 = pctx.getAttrValues().get(attribute1Name).valueAsJson(); + } + log.trace("{} - found values for '{}': {}", getClaimName(), attribute1Name, j1); + + JsonNode j2 = new ArrayNode(JsonNodeFactory.instance); + if (ClaimUtils.isPropSetAndHasAttribute(attribute2Name, pctx)) { + j2 = pctx.getAttrValues().get(attribute2Name).valueAsJson(); + } + log.trace("{} - found values for '{}': {}", getClaimName(), attribute2Name, j2); + + JsonNode result; + if (j1 == null || j1.isNull() || !j1.isArray()) { + result = j2; + } else if (j2 == null || j2.isNull() || !j2.isArray()) { + result = j1; + } else { + ArrayNode a1 = (ArrayNode) j1; + ArrayNode a2 = (ArrayNode) j2; + ArrayNode arr = a1.arrayNode(a1.size() + a2.size()); + arr.addAll(a1); + arr.addAll(a2); + result = arr; + } + log.debug("{} - produced value for user({}): '{}'", getClaimName(), pctx.getPerunUserId(), result); + return result; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/configurations/FacilityAttrsConfig.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/configurations/FacilityAttrsConfig.java new file mode 100644 index 000000000..68753663e --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/configurations/FacilityAttrsConfig.java @@ -0,0 +1,128 @@ +package cz.muni.ics.oidc.server.configurations; + +import java.util.HashSet; +import java.util.Set; +import javax.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Configuration of Facility attributes + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class FacilityAttrsConfig { + + private final static Logger log = LoggerFactory.getLogger(FacilityAttrsConfig.class); + + private String checkGroupMembershipAttr; + private String registrationURLAttr; + private String allowRegistrationAttr; + private String dynamicRegistrationAttr; + private String voShortNamesAttr; + private String wayfFilterAttr; + private String wayfEFilterAttr; + private String testSpAttr; + private final Set<String> membershipAttrNames = new HashSet<>(); + private final Set<String> filterAttrNames = new HashSet<>(); + + public String getCheckGroupMembershipAttr() { + return checkGroupMembershipAttr; + } + + public void setCheckGroupMembershipAttr(String checkGroupMembershipAttr) { + membershipAttrNames.remove(this.checkGroupMembershipAttr); + membershipAttrNames.add(checkGroupMembershipAttr); + this.checkGroupMembershipAttr = checkGroupMembershipAttr; + } + + public String getRegistrationURLAttr() { + return registrationURLAttr; + } + + public void setRegistrationURLAttr(String registrationURLAttr) { + membershipAttrNames.remove(this.registrationURLAttr); + membershipAttrNames.add(registrationURLAttr); + this.registrationURLAttr = registrationURLAttr; + } + + public String getAllowRegistrationAttr() { + return allowRegistrationAttr; + } + + public void setAllowRegistrationAttr(String allowRegistrationAttr) { + membershipAttrNames.remove(this.allowRegistrationAttr); + membershipAttrNames.add(allowRegistrationAttr); + this.allowRegistrationAttr = allowRegistrationAttr; + } + + public String getDynamicRegistrationAttr() { + return dynamicRegistrationAttr; + } + + public void setDynamicRegistrationAttr(String dynamicRegistrationAttr) { + membershipAttrNames.remove(this.dynamicRegistrationAttr); + membershipAttrNames.add(dynamicRegistrationAttr); + this.dynamicRegistrationAttr = dynamicRegistrationAttr; + } + + public String getVoShortNamesAttr() { + return voShortNamesAttr; + } + + public void setVoShortNamesAttr(String voShortNamesAttr) { + membershipAttrNames.remove(this.voShortNamesAttr); + membershipAttrNames.add(voShortNamesAttr); + this.voShortNamesAttr = voShortNamesAttr; + } + + public String getWayfFilterAttr() { + return wayfFilterAttr; + } + + public void setWayfFilterAttr(String wayfFilterAttr) { + filterAttrNames.remove(this.wayfFilterAttr); + filterAttrNames.add(wayfFilterAttr); + this.wayfFilterAttr = wayfFilterAttr; + } + + public String getWayfEFilterAttr() { + return wayfEFilterAttr; + } + + public void setWayfEFilterAttr(String wayfEFilterAttr) { + filterAttrNames.remove(this.wayfEFilterAttr); + filterAttrNames.add(wayfEFilterAttr); + this.wayfEFilterAttr = wayfEFilterAttr; + } + + public Set<String> getMembershipAttrNames() { + return membershipAttrNames; + } + + public Set<String> getFilterAttrNames() { + return filterAttrNames; + } + + public String getTestSpAttr() { + return testSpAttr; + } + + public void setTestSpAttr(String testSpAttr) { + this.testSpAttr = testSpAttr; + } + + @PostConstruct + public void postInit() { + log.info("Facility attributes initialized"); + log.info("Check group membership attr mapped to urn: {}", checkGroupMembershipAttr); + log.info("Allow registration attr mapped to urn: {}", allowRegistrationAttr); + log.info("Registration URL attr mapped to urn: {}", registrationURLAttr); + log.info("Allow dynamic registration attr mapped to urn: {}", dynamicRegistrationAttr); + log.info("Vo short names attr mapped to urn: {}", voShortNamesAttr); + log.info("IDP Filter attr mapped to urn: {}", wayfFilterAttr); + log.info("IDP E-Filter attr mapped to urn: {}", wayfEFilterAttr); + log.info("Test SP attr mapped to urn: {}", testSpAttr); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/configurations/PerunOidcConfig.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/configurations/PerunOidcConfig.java new file mode 100644 index 000000000..c65262e19 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/configurations/PerunOidcConfig.java @@ -0,0 +1,275 @@ +package cz.muni.ics.oidc.server.configurations; + +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.web.util.UriComponentsBuilder; + +/** + * Configuration of OIDC server in context of Perun. + * Logs some interesting facts. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class PerunOidcConfig { + private final static Logger log = LoggerFactory.getLogger(PerunOidcConfig.class); + private static final String OIDC_POM_FILE = "/META-INF/maven/cz.muni.ics/perun-oidc-server-webapp/pom.properties"; + + private ConfigurationPropertiesBean configBean; + private String rpcUrl; + private String jwk; + private String jdbcUrl; + private String theme; + private String baseURL; + private String registrarUrl; + private String samlLoginURL; + private String samlLogoutURL; + private String samlResourcesURL; + private boolean askPerunForIdpFiltersEnabled; + private String perunOIDCVersion; + private String proxyExtSourceName; + private Set<String> idTokenScopes; + private List<String> availableLangs; + private boolean fillMissingUserAttrs; + private boolean addClientIdToAcrs = false; + + @Autowired + private ServletContext servletContext; + + @Autowired + private Properties coreProperties; + private String localizationFilesPath; + private String webClassesFilePath; + private String emailContact; + private String rpcEnabled; + + public void setRpcUrl(String rpcUrl) { + this.rpcUrl = rpcUrl; + } + + public void setConfigBean(ConfigurationPropertiesBean configBean) { + this.configBean = configBean; + } + + public void setJwk(String jwk) { + this.jwk = jwk; + } + + public void setJdbcUrl(String jdbcUrl) { + this.jdbcUrl = jdbcUrl; + } + + public void setTheme(String theme) { + this.theme = theme; + } + + public String getTheme() { + return theme; + } + + public String getBaseURL() { + return baseURL; + } + + public void setBaseURL(String baseURL) { + this.baseURL = baseURL; + } + + public String getSamlResourcesURL() { + return samlResourcesURL; + } + + public void setSamlResourcesURL(String samlResourcesURL) { + this.samlResourcesURL = samlResourcesURL; + } + + public String getRegistrarUrl() { + return registrarUrl; + } + + public void setRegistrarUrl(String registrarUrl) { + this.registrarUrl = registrarUrl; + } + + public void setIdTokenScopes(Set<String> idTokenScopes) { + this.idTokenScopes = idTokenScopes; + } + + public Set<String> getIdTokenScopes() { + return idTokenScopes; + } + + public String getPerunOIDCVersion() { + if (perunOIDCVersion == null) { + perunOIDCVersion = readPomVersion(OIDC_POM_FILE); + } + return perunOIDCVersion; + } + + private String readPomVersion(String file) { + try { + Properties p = new Properties(); + p.load(servletContext.getResourceAsStream(file)); + return p.getProperty("version"); + } catch (IOException e) { + log.error("cannot read file " + file, e); + return "UNKNOWN"; + } + } + + public void setSamlLoginURL(String samlLoginURL) { + this.samlLoginURL = samlLoginURL; + } + + public String getSamlLoginURL() { + return samlLoginURL; + } + + public void setSamlLogoutURL(String samlLogoutURL) { + this.samlLogoutURL = samlLogoutURL; + } + + public String getSamlLogoutURL() { + return samlLogoutURL; + } + + public ConfigurationPropertiesBean getConfigBean() { + return configBean; + } + + public boolean isAskPerunForIdpFiltersEnabled() { + return askPerunForIdpFiltersEnabled; + } + + public void setAskPerunForIdpFiltersEnabled(boolean askPerunForIdpFiltersEnabled) { + this.askPerunForIdpFiltersEnabled = askPerunForIdpFiltersEnabled; + } + + public String getProxyExtSourceName() { + return proxyExtSourceName; + } + + public void setProxyExtSourceName(String proxyExtSourceName) { + if (proxyExtSourceName == null || proxyExtSourceName.isEmpty()) { + this.proxyExtSourceName = null; + } else { + this.proxyExtSourceName = proxyExtSourceName; + } + } + + public List<String> getAvailableLangs() { + return availableLangs; + } + + public void setAvailableLangs(List<String> availableLangs) { + this.availableLangs = availableLangs; + } + + public String getLocalizationFilesPath() { + return localizationFilesPath; + } + + public void setLocalizationFilesPath(String localizationFilesPath) { + this.localizationFilesPath = localizationFilesPath; + } + + public boolean isFillMissingUserAttrs() { + return fillMissingUserAttrs; + } + + public void setFillMissingUserAttrs(boolean fillMissingUserAttrs) { + this.fillMissingUserAttrs = fillMissingUserAttrs; + } + + public String getWebClassesFilePath() { + return webClassesFilePath; + } + + public void setWebClassesFilePath(String webClassesFilePath) { + this.webClassesFilePath = webClassesFilePath; + } + + public String getEmailContact() { + return emailContact; + } + + public void setEmailContact(String emailContact) { + this.emailContact = emailContact; + } + + + public void setRpcEnabled(String rpcEnabled) { + this.rpcEnabled = rpcEnabled; + } + + public String getRpcEnabled() { + return rpcEnabled; + } + + public boolean isAddClientIdToAcrs() { + return addClientIdToAcrs; + } + + public void setAddClientIdToAcrs(boolean addClientIdToAcrs) { + this.addClientIdToAcrs = addClientIdToAcrs; + } + + @PostConstruct + public void postInit() { + //load URLs from properties if available or construct them from issuer URL + if (samlLoginURL != null && !samlLoginURL.trim().isEmpty()) { + samlLoginURL = samlLoginURL.trim(); + } else { + samlLoginURL = UriComponentsBuilder.fromHttpUrl(configBean.getIssuer()).replacePath("/Shibboleth.sso/Login").build().toString(); + } + + if (samlLogoutURL != null && !samlLogoutURL.trim().isEmpty()) { + samlLogoutURL = samlLogoutURL.trim(); + } else { + samlLogoutURL = UriComponentsBuilder.fromHttpUrl(configBean.getIssuer()).replacePath("/Shibboleth.sso/Logout").build().toString(); + } + + if (samlResourcesURL != null && !samlResourcesURL.trim().isEmpty()) { + samlResourcesURL = samlResourcesURL.trim(); + } else { + samlResourcesURL = UriComponentsBuilder.fromHttpUrl(configBean.getIssuer()).replacePath("/proxy").build().toString(); + } + } + + //called when all beans are initialized, but twice, once for root context and once for spring-servlet + @EventListener + public void handleContextRefresh(ContextRefreshedEvent event) { + if (event.getApplicationContext().getParent() == null) { + //log info + log.info("Perun OIDC initialized"); + log.info("Mitreid config URL: {}", configBean.getIssuer()); + log.info("RPC URL: {}", rpcUrl); + log.info("JSON Web Keys: {}", jwk); + log.info("JDBC URL: {}", jdbcUrl); + log.info("LDAP: ldaps://{}/{}", coreProperties.getProperty("ldap.host"), coreProperties.getProperty("ldap.baseDN")); + log.info("FILL MISSING USER ATTRS: {}", fillMissingUserAttrs); + log.info("THEME: {}", theme); + log.info("baseURL: {}", baseURL); + log.info("LOGIN URL: {}", samlLoginURL); + log.info("LOGOUT URL: {}", samlLogoutURL); + log.info("samlResourcesURL: {}", samlResourcesURL); + log.info("Registrar URL: {}", registrarUrl); + log.info("accessTokenClaimsModifier: {}", coreProperties.getProperty("accessTokenClaimsModifier")); + log.info("Proxy EXT_SOURCE name: {}", proxyExtSourceName); + log.info("Available languages: {}", availableLangs); + log.info("Localization files path: {}", localizationFilesPath); + log.info("Email contact: {}", emailContact); + log.info("Perun OIDC version: {}", getPerunOIDCVersion()); + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/connectors/Affiliation.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/connectors/Affiliation.java new file mode 100644 index 000000000..1544e1202 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/connectors/Affiliation.java @@ -0,0 +1,41 @@ +package cz.muni.ics.oidc.server.connectors; + +/** + * Model representing affilitation of user. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class Affiliation { + + private final String source; + private final String value; + private final long asserted; + + public Affiliation(String source, String value, long asserted) { + this.source = source; + this.value = value; + this.asserted = asserted; + } + + public String getSource() { + return source; + } + + public String getValue() { + return value; + } + + public long getAsserted() { + return asserted; + } + + @Override + public String toString() { + return "Affiliation{" + + "source='" + source + '\'' + + ", value='" + value + '\'' + + ", asserted=" + asserted + + '}'; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/connectors/PerunConnectorLdap.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/connectors/PerunConnectorLdap.java new file mode 100644 index 000000000..edc3d3d06 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/connectors/PerunConnectorLdap.java @@ -0,0 +1,147 @@ +package cz.muni.ics.oidc.server.connectors; + +import com.google.common.base.Strings; +import cz.muni.ics.oidc.aop.LogTimes; +import java.util.List; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.apache.directory.api.ldap.model.message.SearchScope; +import org.apache.directory.api.ldap.model.name.Dn; +import org.apache.directory.ldap.client.api.DefaultLdapConnectionFactory; +import org.apache.directory.ldap.client.api.DefaultPoolableLdapConnectionFactory; +import org.apache.directory.ldap.client.api.LdapConnectionConfig; +import org.apache.directory.ldap.client.api.LdapConnectionPool; +import org.apache.directory.ldap.client.api.NoVerificationTrustManager; +import org.apache.directory.ldap.client.api.search.FilterBuilder; +import org.apache.directory.ldap.client.template.EntryMapper; +import org.apache.directory.ldap.client.template.LdapConnectionTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; + +/** + * Connector for calling Perun LDAP + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class PerunConnectorLdap implements DisposableBean { + + private static final Logger log = LoggerFactory.getLogger(PerunConnectorLdap.class); + + private final String baseDN; + private final LdapConnectionPool pool; + private final LdapConnectionTemplate ldap; + + public PerunConnectorLdap(String ldapHost, String ldapUser, String ldapPassword, int port, boolean useTLS, + boolean useSSL, boolean allowUntrustedSsl, long timeoutSecs, String baseDN) { + if (ldapHost == null || ldapHost.trim().isEmpty()) { + throw new IllegalArgumentException("Host cannot be null or empty"); + } else if (baseDN == null || baseDN.trim().isEmpty()) { + throw new IllegalArgumentException("baseDN cannot be null or empty"); + } + + this.baseDN = baseDN; + LdapConnectionConfig config = getConfig(ldapHost, port, useTLS, useSSL, allowUntrustedSsl); + if (ldapUser != null && !ldapUser.isEmpty()) { + log.debug("setting ldap user to {}", ldapUser); + config.setName(ldapUser); + } + if (ldapPassword != null && !ldapPassword.isEmpty()) { + log.debug("setting ldap password"); + config.setCredentials(ldapPassword); + } + DefaultLdapConnectionFactory factory = new DefaultLdapConnectionFactory(config); + factory.setTimeOut(timeoutSecs * 1000L); + + GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); + poolConfig.setTestOnBorrow(true); + + pool = new LdapConnectionPool(new DefaultPoolableLdapConnectionFactory(factory), poolConfig); + ldap = new LdapConnectionTemplate(pool); + log.debug("initialized LDAP connector"); + } + + public String getBaseDN() { + return baseDN; + } + + private LdapConnectionConfig getConfig(String host, int port, boolean useTLS, boolean useSSL, + boolean allowUntrustedSsl) { + LdapConnectionConfig config = new LdapConnectionConfig(); + config.setLdapHost(host); + config.setLdapPort(port); + config.setUseSsl(useSSL); + config.setUseTls(useTLS); + if (allowUntrustedSsl) { + config.setTrustManagers(new NoVerificationTrustManager()); + } + + return config; + } + + @Override + public void destroy() { + if (!pool.isClosed()) { + pool.close(); + } + } + + /** + * Search for the first entry that satisfies criteria. + * @param dnPrefix Prefix to be added to the base DN. (i.e. ou=People) !DO NOT END WITH A COMMA! + * @param filter Filter for entries + * @param scope Search scope + * @param attributes Attributes to be fetch for entry + * @param entryMapper Mapper of entries to the target class T + * @param <T> Class that the result should be mapped to. + * @return Found entry mapped to target class + */ + @LogTimes + public <T> T searchFirst(String dnPrefix, FilterBuilder filter, SearchScope scope, String[] attributes, + EntryMapper<T> entryMapper) + { + Dn fullDn = getFullDn(dnPrefix); + return ldap.searchFirst(fullDn, filter, scope, attributes, entryMapper); + } + + /** + * Perform lookup for the entry that satisfies criteria. + * @param dnPrefix Prefix to be added to the base DN. (i.e. ou=People) !DO NOT END WITH A COMMA! + * @param attributes Attributes to be fetch for entry + * @param entryMapper Mapper of entries to the target class T + * @param <T> Class that the result should be mapped to. + * @return Found entry mapped to target class + */ + @LogTimes + public <T> T lookup(String dnPrefix, String[] attributes, EntryMapper<T> entryMapper) { + Dn fullDn = getFullDn(dnPrefix); + return ldap.lookup(fullDn, attributes, entryMapper); + } + + /** + * Search for the entries satisfy criteria. + * @param dnPrefix Prefix to be added to the base DN. (i.e. ou=People) !DO NOT END WITH A COMMA! + * @param filter Filter for entries + * @param scope Search scope + * @param attributes Attributes to be fetch for entry + * @param entryMapper Mapper of entries to the target class T + * @param <T> Class that the result should be mapped to. + * @return List of found entries mapped to target class + */ + @LogTimes + public <T> List<T> search(String dnPrefix, FilterBuilder filter, SearchScope scope, String[] attributes, + EntryMapper<T> entryMapper) + { + Dn fullDn = getFullDn(dnPrefix); + return ldap.search(fullDn, filter, scope, attributes, entryMapper); + } + + private Dn getFullDn(String prefix) { + String dn = baseDN; + if (!Strings.isNullOrEmpty(prefix)) { + dn = prefix + "," + baseDN; + } + + return ldap.newDn(dn); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/connectors/PerunConnectorRpc.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/connectors/PerunConnectorRpc.java new file mode 100644 index 000000000..c41b05e4b --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/connectors/PerunConnectorRpc.java @@ -0,0 +1,183 @@ +package cz.muni.ics.oidc.server.connectors; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import cz.muni.ics.oidc.aop.LogTimes; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.apache.http.HeaderElement; +import org.apache.http.HeaderElementIterator; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.conn.ConnectionKeepAliveStrategy; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicHeaderElementIterator; +import org.apache.http.protocol.HTTP; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.client.InterceptingClientHttpRequestFactory; +import org.springframework.http.client.support.BasicAuthorizationInterceptor; +import org.springframework.util.StringUtils; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +/** + * Connector for calling Perun RPC + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class PerunConnectorRpc { + + private static final Logger log = LoggerFactory.getLogger(PerunConnectorRpc.class); + + public static final String ATTRIBUTES_MANAGER = "attributesManager"; + public static final String FACILITIES_MANAGER = "facilitiesManager"; + public static final String GROUPS_MANAGER = "groupsManager"; + public static final String MEMBERS_MANAGER = "membersManager"; + public static final String REGISTRAR_MANAGER = "registrarManager"; + public static final String SEARCHER = "searcher"; + public static final String USERS_MANAGER = "usersManager"; + public static final String VOS_MANAGER = "vosManager"; + public static final String RESOURCES_MANAGER = "resourcesManager"; + + private String perunUrl; + private String perunUser; + private String perunPassword; + private boolean isEnabled; + private String serializer; + private RestTemplate restTemplate; + + public PerunConnectorRpc(String perunUrl, String perunUser, String perunPassword, String enabled, String serializer) { + this.isEnabled = Boolean.parseBoolean(enabled); + this.setPerunUrl(perunUrl); + this.setPerunUser(perunUser); + this.setPerunPassword(perunPassword); + this.setSerializer(serializer); + } + + public void setEnabled(String enabled) { + this.isEnabled = Boolean.parseBoolean(enabled); + } + + public boolean isEnabled() { + return isEnabled; + } + + public void setPerunUrl(String perunUrl) { + if (!StringUtils.hasText(perunUrl)) { + throw new IllegalArgumentException("Perun URL cannot be null or empty"); + } else if (perunUrl.endsWith("/")) { + perunUrl = perunUrl.substring(0, perunUrl.length() - 1); + } + + this.perunUrl = perunUrl; + } + + public void setPerunUser(String perunUser) { + if (!StringUtils.hasText(perunUser)) { + throw new IllegalArgumentException("Perun USER cannot be null or empty"); + } + + this.perunUser = perunUser; + } + + public void setPerunPassword(String perunPassword) { + if (!StringUtils.hasText(perunPassword)) { + throw new IllegalArgumentException("Perun PASSWORD cannot be null or empty"); + } + + this.perunPassword = perunPassword; + } + + public void setSerializer(String serializer) { + if (!StringUtils.hasText(serializer)) { + this.serializer = "json"; + } + + this.serializer = serializer; + } + + @PostConstruct + public void postInit() { + restTemplate = new RestTemplate(); + //HTTP connection pooling, see https://howtodoinjava.com/spring-restful/resttemplate-httpclient-java-config/ + RequestConfig requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(30000) // The timeout when requesting a connection from the connection manager + .setConnectTimeout(30000) // Determines the timeout in milliseconds until a connection is established + .setSocketTimeout(60000) // The timeout for waiting for data + .build(); + PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(); + poolingConnectionManager.setMaxTotal(20); // maximum connections total + poolingConnectionManager.setDefaultMaxPerRoute(18); + ConnectionKeepAliveStrategy connectionKeepAliveStrategy = (response, context) -> { + HeaderElementIterator it = new BasicHeaderElementIterator + (response.headerIterator(HTTP.CONN_KEEP_ALIVE)); + while (it.hasNext()) { + HeaderElement he = it.nextElement(); + String param = he.getName(); + String value = he.getValue(); + + if (value != null && param.equalsIgnoreCase("timeout")) { + return Long.parseLong(value) * 1000; + } + } + return 20000L; + }; + CloseableHttpClient httpClient = HttpClients.custom() + .setDefaultRequestConfig(requestConfig) + .setConnectionManager(poolingConnectionManager) + .setKeepAliveStrategy(connectionKeepAliveStrategy) + .build(); + HttpComponentsClientHttpRequestFactory poolingRequestFactory = new HttpComponentsClientHttpRequestFactory(); + poolingRequestFactory.setHttpClient(httpClient); + //basic authentication + List<ClientHttpRequestInterceptor> interceptors = + Collections.singletonList(new BasicAuthorizationInterceptor(perunUser, perunPassword)); + InterceptingClientHttpRequestFactory authenticatingRequestFactory = new InterceptingClientHttpRequestFactory(poolingRequestFactory, interceptors); + restTemplate.setRequestFactory(authenticatingRequestFactory); + } + + /** + * Make post call to Perun RPC + * @param manager String value representing manager to be called. Use constants from this class. + * @param method Method to be called (i.e. getUserById) + * @param map Map of parameters to be passed as request body + * @return Response from Perun + */ + @LogTimes + public JsonNode post(String manager, String method, Map<String, Object> map) { + if (!this.isEnabled) { + return JsonNodeFactory.instance.nullNode(); + } + + String actionUrl = perunUrl + '/' + serializer + '/' + manager + '/' + method; + //make the call + try { + log.debug("calling {} with {}", actionUrl, map); + return restTemplate.postForObject(actionUrl, map, JsonNode.class); + } catch (HttpClientErrorException ex) { + MediaType contentType = ex.getResponseHeaders().getContentType(); + String body = ex.getResponseBodyAsString(); + log.error("HTTP ERROR " + ex.getRawStatusCode() + " URL " + actionUrl + " Content-Type: " + contentType); + if ("json".equals(contentType.getSubtype())) { + try { + log.error(new ObjectMapper().readValue(body, JsonNode.class).path("message").asText()); + } catch (IOException e) { + log.error("cannot parse error message from JSON", e); + } + } else { + log.error(ex.getMessage()); + } + throw new RuntimeException("cannot connect to Perun RPC", ex); + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/AddHeaderInterceptor.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/AddHeaderInterceptor.java new file mode 100644 index 000000000..70576bc7b --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/AddHeaderInterceptor.java @@ -0,0 +1,30 @@ +package cz.muni.ics.oidc.server.elixir; + +import java.io.IOException; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; + +/** + * HTTP Request Interceptor which adds a specific header to the request. + * Name of the header and value are passed in constructor. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +class AddHeaderInterceptor implements ClientHttpRequestInterceptor { + + private final String header; + private final String value; + + AddHeaderInterceptor(String header, String value) { + this.header = header; + this.value = value; + } + + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { + request.getHeaders().add(header, value); + return execution.execute(request, body); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/ElixirAccessTokenModifier.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/ElixirAccessTokenModifier.java new file mode 100644 index 000000000..b4709d903 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/ElixirAccessTokenModifier.java @@ -0,0 +1,36 @@ +package cz.muni.ics.oidc.server.elixir; + +import com.nimbusds.jwt.JWTClaimsSet; +import cz.muni.ics.oidc.server.PerunAccessTokenEnhancer; +import java.util.Collections; +import java.util.Set; +import cz.muni.ics.openid.connect.model.UserInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; + +/** + * Implements changes required by GA4GH specification followed by the ELIXIR AAI. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +@SuppressWarnings("unused") +public class ElixirAccessTokenModifier implements PerunAccessTokenEnhancer.AccessTokenClaimsModifier { + + private final static Logger log = LoggerFactory.getLogger(ElixirAccessTokenModifier.class); + + public ElixirAccessTokenModifier() { + } + + @Override + public void modifyClaims(String sub, JWTClaimsSet.Builder builder, OAuth2AccessToken accessToken, OAuth2Authentication authentication, UserInfo userInfo) { + Set<String> scopes = accessToken.getScope(); + //GA4GH + if (scopes.contains(GA4GHClaimSource.GA4GH_SCOPE)) { + log.debug("adding claims required by GA4GH to access token"); + builder.audience(Collections.singletonList(authentication.getOAuth2Request().getClientId())); + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/GA4GHClaimSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/GA4GHClaimSource.java new file mode 100644 index 000000000..37e6935c2 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/GA4GHClaimSource.java @@ -0,0 +1,593 @@ +package cz.muni.ics.oidc.server.elixir; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; +import com.nimbusds.jose.JOSEObjectType; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.Payload; +import com.nimbusds.jose.crypto.RSASSAVerifier; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.JWKMatcher; +import com.nimbusds.jose.jwk.JWKSelector; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.source.RemoteJWKSet; +import com.nimbusds.jose.proc.SecurityContext; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.JWTParser; +import com.nimbusds.jwt.SignedJWT; +import cz.muni.ics.oidc.models.PerunAttribute; +import cz.muni.ics.oidc.server.claims.ClaimSource; +import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext; +import cz.muni.ics.oidc.server.connectors.Affiliation; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLEncoder; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.openid.connect.web.JWKSetPublishingEndpoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; +import org.springframework.http.client.InterceptingClientHttpRequestFactory; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +/** + * Class producing GA4GH Passport claim. The claim is specified in + * https://bit.ly/ga4gh-passport-v1 + * + * Configuration (replace [claimName] with the name of the claim): + * <ul> + * <li><b>custom.claim.[claimName].source.config_file</b> - full path to the configuration file for this claim. See + * configuration templates for such a file.</li> + * <li><b>custom.claim.[claimName].source.bonaFideStatus.attr</b> - mapping for bonaFideStatus Attriute</li> + * <li><b>custom.claim.[claimName].source.bonaFideStatusREMS.attr</b> - mapping for bonaFideStatus Attriute</li> + * <li><b>custom.claim.[claimName].source.groupAffiliations.attr</b> - mapping for groupAffiliations Attriute</li> + * </ul> + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class GA4GHClaimSource extends ClaimSource { + + static final String GA4GH_SCOPE = "ga4gh_passport_v1"; + private static final String GA4GH_CLAIM = "ga4gh_passport_v1"; + + private static final Logger log = LoggerFactory.getLogger(GA4GHClaimSource.class); + + private static final String BONA_FIDE_URL = "https://doi.org/10.1038/s41431-018-0219-y"; + private static final String ELIXIR_ORG_URL = "https://elixir-europe.org/"; + private static final String ELIXIR_ID = "elixir_id"; + + private final JWTSigningAndValidationService jwtService; + private final URI jku; + private final String issuer; + private static final List<ClaimRepository> claimRepositories = new ArrayList<>(); + private static final Map<URI, RemoteJWKSet<SecurityContext>> remoteJwkSets = new HashMap<>(); + private static final Map<URI, String> signers = new HashMap<>(); + + private final String bonaFideStatusAttr; + private final String bonaFideStatusREMSAttr; + private final String groupAffiliationsAttr; + + public GA4GHClaimSource(ClaimSourceInitContext ctx) throws URISyntaxException { + super(ctx); + log.debug("initializing"); + //remember context + jwtService = ctx.getJwtService(); + issuer = ctx.getPerunOidcConfig().getConfigBean().getIssuer(); + jku = new URI(issuer + JWKSetPublishingEndpoint.URL); + // load config file + parseConfigFile(ctx.getProperty("config_file", "/etc/mitreid/elixir/ga4gh_config.yml")); + bonaFideStatusAttr = ctx.getProperty("bonaFideStatus.attr", null); + bonaFideStatusREMSAttr = ctx.getProperty("bonaFideStatusREMS.attr", null); + groupAffiliationsAttr = ctx.getProperty("groupAffiliations.attr", null); + } + + static void parseConfigFile(String file) { + YAMLMapper mapper = new YAMLMapper(); + try { + JsonNode root = mapper.readValue(new File(file), JsonNode.class); + // prepare claim repositories + for (JsonNode repo : root.path("repos")) { + String name = repo.path("name").asText(); + String actionURL = repo.path("url").asText(); + JsonNode headers = repo.path("headers"); + Map<String, String> headersWithValues = new HashMap<>(); + for (JsonNode header: headers) { + headersWithValues.put(header.path("header").asText(), header.path("value").asText()); + } + if (actionURL == null || headersWithValues.isEmpty()) { + log.error("claim repository " + repo + " not defined with url|auth_header|auth_value "); + continue; + } + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setRequestFactory( + new InterceptingClientHttpRequestFactory(restTemplate.getRequestFactory(), + headersWithValues.entrySet() + .stream() + .map(e -> new AddHeaderInterceptor(e.getKey(), e.getValue())) + .collect(Collectors.toList())) + ); + claimRepositories.add(new ClaimRepository(name, restTemplate, actionURL)); + log.info("GA4GH Claims Repository " + name + " configured at " + actionURL); + } + // prepare claim signers + for (JsonNode signer : root.path("signers")) { + String name = signer.path("name").asText(); + String jwks = signer.path("jwks").asText(); + try { + URL jku = new URL(jwks); + remoteJwkSets.put(jku.toURI(), new RemoteJWKSet<>(jku)); + signers.put(jku.toURI(), name); + log.info("JWKS Signer " + name + " added with keys " + jwks); + } catch (MalformedURLException | URISyntaxException e) { + log.error("cannot add to RemoteJWKSet map: " + name + " " + jwks, e); + } + } + } catch (IOException ex) { + log.error("cannot read GA4GH config file", ex); + } + } + + @Override + public Set<String> getAttrIdentifiers() { + Set<String> set = new HashSet<>(); + if (bonaFideStatusAttr != null) { + set.add(bonaFideStatusAttr); + } + if (bonaFideStatusREMSAttr != null) { + set.add(bonaFideStatusREMSAttr); + } + if (groupAffiliationsAttr != null) { + set.add(groupAffiliationsAttr); + } + return set; + } + + @Override + public JsonNode produceValue(ClaimSourceProduceContext pctx) { + if (pctx.getClient() == null) { + log.debug("client is not set"); + return JsonNodeFactory.instance.textNode("Global Alliance For Genomic Health structured claim"); + } + if (!pctx.getClient().getScope().contains(GA4GH_SCOPE)) { + log.debug("Client '{}' does not have scope ga4gh", pctx.getClient().getClientName()); + return null; + } + + List<Affiliation> affiliations = pctx.getPerunAdapter() + .getAdapterRpc() + .getUserExtSourcesAffiliations(pctx.getPerunUserId()); + + ArrayNode ga4gh_passport_v1 = JsonNodeFactory.instance.arrayNode(); + long now = Instant.now().getEpochSecond(); + addAffiliationAndRoles(now, pctx, ga4gh_passport_v1, affiliations); + addAcceptedTermsAndPolicies(now, pctx, ga4gh_passport_v1); + addResearcherStatuses(now, pctx, ga4gh_passport_v1, affiliations); + addControlledAccessGrants(now, pctx, ga4gh_passport_v1); + return ga4gh_passport_v1; + } + + + private void addAffiliationAndRoles(long now, ClaimSourceProduceContext pctx, ArrayNode passport, List<Affiliation> affiliations) { + //by=system for users with affiliation asserted by their IdP (set in UserExtSource attribute "affiliation") + for (Affiliation affiliation : affiliations) { + //expires 1 year after the last login from the IdP asserting the affiliation + long expires = Instant.ofEpochSecond(affiliation.getAsserted()).atZone(ZoneId.systemDefault()).plusYears(1L).toEpochSecond(); + if (expires < now) continue; + JsonNode visa = createPassportVisa("AffiliationAndRole", pctx, affiliation.getValue(), affiliation.getSource(), "system", affiliation.getAsserted(), expires, null); + if (visa != null) { + passport.add(visa); + } + } + } + + private void addAcceptedTermsAndPolicies(long now, ClaimSourceProduceContext pctx, ArrayNode passport) { + //by=self for members of the group 10432 "Bona Fide Researchers" + boolean userInGroup = pctx.getPerunAdapter().isUserInGroup(pctx.getPerunUserId(), 10432L); + if (userInGroup) { + PerunAttribute bonaFideStatus = pctx.getPerunAdapter() + .getAdapterRpc() + .getUserAttribute(pctx.getPerunUserId(), bonaFideStatusAttr); + String valueCreatedAt = bonaFideStatus.getValueCreatedAt(); + long asserted; + if (valueCreatedAt != null) { + asserted = Timestamp.valueOf(valueCreatedAt).getTime() / 1000L; + } else { + asserted = System.currentTimeMillis() / 1000L; + } + long expires = Instant.ofEpochSecond(asserted).atZone(ZoneId.systemDefault()).plusYears(100L).toEpochSecond(); + if (expires < now) return; + JsonNode visa = createPassportVisa("AcceptedTermsAndPolicies", pctx, BONA_FIDE_URL, ELIXIR_ORG_URL, "self", asserted, expires, null); + if (visa != null) { + passport.add(visa); + } + } + } + + private void addResearcherStatuses(long now, ClaimSourceProduceContext pctx, ArrayNode passport, List<Affiliation> affiliations) { + //by=peer for users with attribute elixirBonaFideStatusREMS + PerunAttribute elixirBonaFideStatusREMS = pctx.getPerunAdapter() + .getAdapterRpc() + .getUserAttribute(pctx.getPerunUserId(), bonaFideStatusREMSAttr); + + String valueCreatedAt = null; + if (elixirBonaFideStatusREMS != null) { + valueCreatedAt = elixirBonaFideStatusREMS.getValueCreatedAt(); + } + + if (valueCreatedAt != null) { + long asserted = Timestamp.valueOf(valueCreatedAt).getTime() / 1000L; + long expires = ZonedDateTime.now().plusYears(1L).toEpochSecond(); + if (expires > now) { + JsonNode visa = createPassportVisa("ResearcherStatus", pctx, BONA_FIDE_URL, ELIXIR_ORG_URL, "peer", asserted, expires, null); + if (visa != null) { + passport.add(visa); + } + } + } + //by=system for users with faculty affiliation asserted by their IdP (set in UserExtSource attribute "affiliation") + for (Affiliation affiliation : affiliations) { + if (affiliation.getValue().startsWith("faculty@")) { + long expires = Instant.ofEpochSecond(affiliation.getAsserted()).atZone(ZoneId.systemDefault()).plusYears(1L).toEpochSecond(); + if (expires < now) continue; + JsonNode visa = createPassportVisa("ResearcherStatus", pctx, BONA_FIDE_URL, affiliation.getSource(), "system", affiliation.getAsserted(), expires, null); + if (visa != null) { + passport.add(visa); + } + } + } + //by=so for users with faculty affiliation asserted by membership in a group with groupAffiliations attribute + for (Affiliation affiliation : pctx.getPerunAdapter().getGroupAffiliations(pctx.getPerunUserId(), groupAffiliationsAttr)) { + if (affiliation.getValue().startsWith("faculty@")) { + long expires = ZonedDateTime.now().plusYears(1L).toEpochSecond(); + JsonNode visa = createPassportVisa("ResearcherStatus", pctx, BONA_FIDE_URL, ELIXIR_ORG_URL, "so", affiliation.getAsserted(), expires, null); + if (visa != null) { + passport.add(visa); + } + } + } + } + + private static String isoDate(long linuxTime) { + return DateTimeFormatter.ISO_LOCAL_DATE.format(ZonedDateTime.ofInstant(Instant.ofEpochSecond(linuxTime), ZoneId.systemDefault())); + } + + private static String isoDateTime(long linuxTime) { + return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(ZonedDateTime.ofInstant(Instant.ofEpochSecond(linuxTime), ZoneId.systemDefault())); + } + + private JsonNode createPassportVisa(String type, ClaimSourceProduceContext pctx, String value, String source, String by, long asserted, long expires, JsonNode condition) { + long now = System.currentTimeMillis() / 1000L; + if (asserted > now) { + log.warn("visa asserted in future ! perunUserId {} sub {} type {} value {} source {} by {} asserted {}", pctx.getPerunUserId(), pctx.getSub(), type, value, source, by, Instant.ofEpochSecond(asserted)); + return null; + } + if (expires <= now) { + log.warn("visa already expired ! perunUserId {} sub {} type {} value {} source {} by {} expired {}", pctx.getPerunUserId(), pctx.getSub(), type, value, source, by, Instant.ofEpochSecond(expires)); + return null; + } + + Map<String, Object> passportVisaObject = new HashMap<>(); + passportVisaObject.put("type", type); + passportVisaObject.put("asserted", asserted); + passportVisaObject.put("value", value); + passportVisaObject.put("source", source); + passportVisaObject.put("by", by); + if (condition != null && !condition.isNull() && !condition.isMissingNode()) { + passportVisaObject.put("condition", condition); + } + JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.parse(jwtService.getDefaultSigningAlgorithm().getName())) + .keyID(jwtService.getDefaultSignerKeyId()) + .type(JOSEObjectType.JWT) + .jwkURL(jku) + .build(); + JWTClaimsSet jwtClaimsSet = new JWTClaimsSet.Builder() + .issuer(issuer) + .issueTime(new Date()) + .expirationTime(new Date(expires * 1000L)) + .subject(pctx.getSub()) + .jwtID(UUID.randomUUID().toString()) + .claim("ga4gh_visa_v1", passportVisaObject) + .build(); + SignedJWT myToken = new SignedJWT(jwsHeader, jwtClaimsSet); + jwtService.signJwt(myToken); + return JsonNodeFactory.instance.textNode(myToken.serialize()); + } + + private void addControlledAccessGrants(long now, ClaimSourceProduceContext pctx, ArrayNode passport) { + Set<String> linkedIdentities = new HashSet<>(); + //call Resource Entitlement Management System + for (ClaimRepository repo : claimRepositories) { + callPermissionsJwtAPI(repo, Collections.singletonMap(ELIXIR_ID, pctx.getSub()), pctx, passport, linkedIdentities); + } + if (!linkedIdentities.isEmpty()) { + for (String linkedIdentity : linkedIdentities) { + JsonNode visa = createPassportVisa("LinkedIdentities", pctx, linkedIdentity, ELIXIR_ORG_URL, "system", now, now + 3600L * 24 * 365, null); + if (visa != null) { + passport.add(visa); + } + } + } + } + + private void callPermissionsJwtAPI(ClaimRepository repo, Map<String, String> uriVariables, ClaimSourceProduceContext pctx, ArrayNode passport, Set<String> linkedIdentities) { + JsonNode response = callHttpJsonAPI(repo, uriVariables); + if (response != null) { + JsonNode visas = response.path(GA4GH_CLAIM); + if (visas.isArray()) { + for (JsonNode visaNode : visas) { + if (visaNode.isTextual()) { + PassportVisa visa = parseAndVerifyVisa(visaNode.asText()); + if (visa.isVerified()) { + log.debug("adding a visa to passport: {}", visa); + passport.add(passport.textNode(visa.getJwt())); + linkedIdentities.add(visa.getLinkedIdentity()); + } else { + log.warn("skipping visa: {}", visa); + } + } else { + log.warn("element of ga4gh_passport_v1 is not a String: {}", visaNode); + } + } + } else { + log.warn("ga4gh_passport_v1 is not an array in {}", response); + } + } + } + + + public static PassportVisa parseAndVerifyVisa(String jwtString) { + PassportVisa visa = new PassportVisa(jwtString); + try { + SignedJWT signedJWT = (SignedJWT) JWTParser.parse(jwtString); + URI jku = signedJWT.getHeader().getJWKURL(); + if (jku == null) { + log.error("JKU is missing in JWT header"); + return visa; + } + visa.setSigner(signers.get(jku)); + RemoteJWKSet<SecurityContext> remoteJWKSet = remoteJwkSets.get(jku); + if (remoteJWKSet == null) { + log.error("JKU {} is not among trusted key sets", jku); + return visa; + } + List<JWK> keys = remoteJWKSet.get(new JWKSelector(new JWKMatcher.Builder().keyID(signedJWT.getHeader().getKeyID()).build()), null); + RSASSAVerifier verifier = new RSASSAVerifier(((RSAKey) keys.get(0)).toRSAPublicKey()); + visa.setVerified(signedJWT.verify(verifier)); + if (visa.isVerified()) { + processPayload(visa, signedJWT.getPayload()); + } + } catch (Exception ex) { + log.error("visa " + jwtString + " cannot be parsed and verified", ex); + } + return visa; + } + + static private final ObjectMapper JSON_MAPPER = new ObjectMapper(); + + static private void processPayload(PassportVisa visa, Payload payload) throws IOException { + JsonNode doc = JSON_MAPPER.readValue(payload.toString(), JsonNode.class); + checkVisaKey(visa, doc, "sub"); + checkVisaKey(visa, doc, "exp"); + checkVisaKey(visa, doc, "iss"); + JsonNode visa_v1 = doc.path("ga4gh_visa_v1"); + checkVisaKey(visa, visa_v1, "type"); + checkVisaKey(visa, visa_v1, "asserted"); + checkVisaKey(visa, visa_v1, "value"); + checkVisaKey(visa, visa_v1, "source"); + checkVisaKey(visa, visa_v1, "by"); + if (!visa.isVerified()) return; + long exp = doc.get("exp").asLong(); + if (exp < Instant.now().getEpochSecond()) { + log.warn("visa expired on " + isoDateTime(exp)); + visa.setVerified(false); + return; + } + visa.setLinkedIdentity(URLEncoder.encode(doc.get("sub").asText(), "utf-8") + "," + URLEncoder.encode(doc.get("iss").asText(), "utf-8")); + visa.setPrettyPayload( + visa_v1.get("type").asText() + ": \"" + visa_v1.get("value").asText() + "\" asserted " + isoDate(visa_v1.get("asserted").asLong()) + ); + } + + static private void checkVisaKey(PassportVisa visa, JsonNode jsonNode, String key) { + if (jsonNode.path(key).isMissingNode()) { + log.warn(key + " is missing"); + visa.setVerified(false); + } else { + switch (key) { + case "sub": + visa.setSub(jsonNode.path(key).asText()); + break; + case "iss": + visa.setIss(jsonNode.path(key).asText()); + break; + case "type": + visa.setType(jsonNode.path(key).asText()); + break; + case "value": + visa.setValue(jsonNode.path(key).asText()); + break; + } + } + } + + @SuppressWarnings("Duplicates") + private static JsonNode callHttpJsonAPI(ClaimRepository repo, Map<String, String> uriVariables) { + //get permissions data + try { + JsonNode result; + //make the call + try { + if (log.isDebugEnabled()) { + log.debug("calling Permissions API at {}", repo.getRestTemplate().getUriTemplateHandler().expand(repo.getActionURL(), uriVariables)); + } + result = repo.getRestTemplate().getForObject(repo.getActionURL(), JsonNode.class, uriVariables); + } catch (HttpClientErrorException ex) { + MediaType contentType = ex.getResponseHeaders().getContentType(); + String body = ex.getResponseBodyAsString(); + log.error("HTTP ERROR " + ex.getRawStatusCode() + " URL " + repo.getActionURL() + " Content-Type: " + contentType); + if (ex.getRawStatusCode() == 404) { + log.warn("Got status 404 from Permissions endpoint {}, ELIXIR AAI user is not linked to user at Permissions API", repo.getActionURL()); + return null; + } + if ("json".equals(contentType.getSubtype())) { + try { + log.error(new ObjectMapper().readValue(body, JsonNode.class).path("message").asText()); + } catch (IOException e) { + log.error("cannot parse error message from JSON", e); + } + } else { + log.error("cannot make REST call, exception: {} message: {}", ex.getClass().getName(), ex.getMessage()); + } + return null; + } + log.debug("Permissions API response: {}", result); + return result; + } catch (Exception ex) { + log.error("Cannot get dataset permissions", ex); + } + return null; + } + + public static class PassportVisa { + String jwt; + boolean verified = false; + String linkedIdentity; + String signer; + String prettyPayload; + private String sub; + private String iss; + private String type; + private String value; + + PassportVisa(String jwt) { + this.jwt = jwt; + } + + public String getJwt() { + return jwt; + } + + public boolean isVerified() { + return verified; + } + + void setVerified(boolean verified) { + this.verified = verified; + } + + String getLinkedIdentity() { + return linkedIdentity; + } + + void setLinkedIdentity(String linkedIdentity) { + this.linkedIdentity = linkedIdentity; + } + + void setSigner(String signer) { + this.signer = signer; + } + + void setPrettyPayload(String prettyPayload) { + this.prettyPayload = prettyPayload; + } + + public String getPrettyString() { + return prettyPayload + ", signed by " + signer; + } + + @Override + public String toString() { + return "PassportVisa{" + +// "jwt='" + jwt + '\'' + + " type=" + type + + ", sub=" + sub + + ", iss=" + iss + + ", value=" + value + + ", verified=" + verified + + ", linkedIdentity=" + linkedIdentity + + '}'; + } + + public void setSub(String sub) { + this.sub = sub; + } + + public String getSub() { + return sub; + } + + public void setIss(String iss) { + this.iss = iss; + } + + public String getIss() { + return iss; + } + + public void setType(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public void setValue(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } + + public static class ClaimRepository { + private String name; + private RestTemplate restTemplate; + private String actionURL; + + public ClaimRepository(String name, RestTemplate restTemplate, String actionURL) { + this.name = name; + this.restTemplate = restTemplate; + this.actionURL = actionURL; + } + + public RestTemplate getRestTemplate() { + return restTemplate; + } + + public String getActionURL() { + return actionURL; + } + + public String getName() { + return name; + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/GA4GHTokenParser.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/GA4GHTokenParser.java new file mode 100644 index 000000000..a705506dd --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/elixir/GA4GHTokenParser.java @@ -0,0 +1,64 @@ +package cz.muni.ics.oidc.server.elixir; + +import static cz.muni.ics.oidc.server.elixir.GA4GHClaimSource.parseAndVerifyVisa; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jwt.JWTParser; +import com.nimbusds.jwt.SignedJWT; +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +/** + * This class is a command-line debugging tool. It parses JSON in GA4GH Passport format, + * verifies signatures on Passport Visas (JWT tokens), and prints them in human-readable format. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class GA4GHTokenParser { + + static ObjectMapper jsonMapper = new ObjectMapper(); + + public static void main(String[] args) throws IOException, ParseException, JOSEException { + GA4GHClaimSource.parseConfigFile("ga4gh_config.yml"); + String userinfo = "/tmp/ga4gh.json"; + JsonNode doc = jsonMapper.readValue(new File(userinfo), JsonNode.class); + JsonNode ga4gh = doc.get("ga4gh_passport_v1"); + long startx = System.currentTimeMillis(); + System.out.println(); + for (JsonNode jwtString : ga4gh) { + String s = jwtString.asText(); + GA4GHClaimSource.PassportVisa visa = parseAndVerifyVisa(s); + if(!visa.isVerified()) { + System.out.println("visa not verified: "+s); + System.out.println("visa = " + visa.getPrettyString()); + +// System.exit(1); + } else { + System.out.println("OK: "+visa.getPrettyString()); + } + SignedJWT jwt = (SignedJWT) JWTParser.parse(s); + ObjectWriter prettyPrinter = jsonMapper.writerWithDefaultPrettyPrinter(); + + JsonNode visaHeader = jsonMapper.readValue(jwt.getHeader().toString(), JsonNode.class); + System.out.println(prettyPrinter.writeValueAsString(visaHeader)); + + JsonNode visaPayload = jsonMapper.readValue(jwt.getPayload().toString(), JsonNode.class); + System.out.println(prettyPrinter.writeValueAsString(visaPayload)); + } + long endx = System.currentTimeMillis(); + System.out.println("signature verification time: " + (endx - startx)); + + } + + private static String isoDateTime(long linuxTime) { + return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(ZonedDateTime.ofInstant(Instant.ofEpochSecond(linuxTime), ZoneId.systemDefault())); + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/CallPerunFiltersFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/CallPerunFiltersFilter.java new file mode 100644 index 000000000..c4a37f603 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/CallPerunFiltersFilter.java @@ -0,0 +1,86 @@ +package cz.muni.ics.oidc.server.filters; + +import cz.muni.ics.oidc.BeanUtil; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import javax.annotation.PostConstruct; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.oauth2.provider.OAuth2RequestFactory; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +/** + * This filter calls other Perun filters saved in the PerunFiltersContext + * + * @author Dominik Baranek <baranek@ics.muni.cz> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class CallPerunFiltersFilter extends GenericFilterBean { + + public static final Logger log = LoggerFactory.getLogger(CallPerunFiltersFilter.class); + + @Autowired + private Properties coreProperties; + + @Autowired + private BeanUtil beanUtil; + + @Autowired + private OAuth2RequestFactory authRequestFactory; + + @Autowired + private ClientDetailsEntityService clientDetailsEntityService; + + @Autowired + private PerunAdapter perunAdapter; + + private PerunFiltersContext perunFiltersContext; + + @PostConstruct + public void postConstruct() { + this.perunFiltersContext = new PerunFiltersContext(coreProperties, beanUtil); + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException + { + List<PerunRequestFilter> filters = perunFiltersContext.getFilters(); + if (filters != null && !filters.isEmpty()) { + HttpServletRequest request = (HttpServletRequest) servletRequest; + ClientDetailsEntity client = FiltersUtils.extractClientFromRequest(request, authRequestFactory, + clientDetailsEntityService); + Facility facility = null; + if (client != null && StringUtils.hasText(client.getClientId())) { + try { + facility = perunAdapter.getFacilityByClientId(client.getClientId()); + } catch (Exception e) { + log.warn("{} - could not fetch facility for client_id '{}'", + CallPerunFiltersFilter.class.getSimpleName(), client.getClientId(), e); + } + } + PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter); + FilterParams params = new FilterParams(client, facility, user); + for (PerunRequestFilter filter : filters) { + if (!filter.doFilter(servletRequest, servletResponse, params)) { + return; + } + } + } + filterChain.doFilter(servletRequest, servletResponse); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/FilterParams.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/FilterParams.java new file mode 100644 index 000000000..b0a92d366 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/FilterParams.java @@ -0,0 +1,39 @@ +package cz.muni.ics.oidc.server.filters; + +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; + +public class FilterParams { + + private final ClientDetailsEntity client; + private final Facility facility; + private final PerunUser user; + + public FilterParams(ClientDetailsEntity client, Facility facility, PerunUser user) { + this.client = client; + this.facility = facility; + this.user = user; + } + + public ClientDetailsEntity getClient() { + return client; + } + + public Facility getFacility() { + return facility; + } + + public PerunUser getUser() { + return user; + } + + public String getClientIdentifier() { + if (client != null) { + return client.getClientId(); + } + + return null; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/FiltersUtils.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/FiltersUtils.java new file mode 100644 index 000000000..156b53aaf --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/FiltersUtils.java @@ -0,0 +1,328 @@ +package cz.muni.ics.oidc.server.filters; + +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_FORCE_AUTHN; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.SAML_EPUID; +import static org.apache.commons.lang3.StringUtils.isNotEmpty; + +import com.google.common.base.Strings; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.server.PerunPrincipal; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig; +import cz.muni.ics.oidc.web.controllers.ControllerUtils; +import cz.muni.ics.oidc.web.controllers.PerunUnapprovedRegistrationController; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.oauth2.provider.AuthorizationRequest; +import org.springframework.security.oauth2.provider.OAuth2RequestFactory; +import org.springframework.security.providers.ExpiringUsernameAuthenticationToken; +import org.springframework.security.saml.SAMLCredential; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; + +/** + * Utility class for filters. Contains common methods used by most of filter classes. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class FiltersUtils { + + private static final Logger log = LoggerFactory.getLogger(FiltersUtils.class); + + private static final RequestMatcher requestMatcher = new AntPathRequestMatcher(PerunFilterConstants.AUTHORIZE_REQ_PATTERN); + + /** + * Create map of request params in format key = name, value = paramValue. + * + * @param parameterMap Original map of parameters + * @return Map of parameters + */ + public static Map<String, String> createRequestMap(Map<String, String[]> parameterMap) { + Map<String, String> requestMap = new HashMap<>(); + for (String key : parameterMap.keySet()) { + String[] val = parameterMap.get(key); + if (val != null && val.length > 0) { + requestMap.put(key, val[0]); // add the first value only (which is what Spring seems to do) + } + } + return requestMap; + } + + /** + * Extract client from request + * + * @param request request to be matched and containing client + * @param authRequestFactory authorization request factory + * @param clientService service fetching client details + * @return extracted client, null if some error occurs + */ + @SuppressWarnings("unchecked") + public static ClientDetailsEntity extractClientFromRequest(HttpServletRequest request, + OAuth2RequestFactory authRequestFactory, + ClientDetailsEntityService clientService) + { + if (!requestMatcher.matches(request) || request.getParameter("response_type") == null) { + return null; + } + + AuthorizationRequest authRequest = authRequestFactory.createAuthorizationRequest( + FiltersUtils.createRequestMap(request.getParameterMap())); + + ClientDetailsEntity client; + if (Strings.isNullOrEmpty(authRequest.getClientId())) { + log.debug("cannot extract client - ClientID is null or empty"); + return null; + } + + client = clientService.loadClientByClientId(authRequest.getClientId()); + if (Strings.isNullOrEmpty(client.getClientName())) { + log.warn("cannot extract clientName for the clientID '{}'", client.getClientId()); + return null; + } + + log.debug("returning client '{}' with ID '{}'", client.getClientId(), client.getClientName()); + return client; + } + + /** + * Get Perun user + * @param request Request object + * @param perunAdapter Adapter of Perun interface + * @return Found PerunUser + */ + public static PerunUser getPerunUser(HttpServletRequest request, PerunAdapter perunAdapter) { + SAMLCredential samlCredential = getSamlCredential(request); + if (samlCredential == null) { + return null; + } + PerunPrincipal principal = getPerunPrincipal(samlCredential); + log.debug("fetching Perun user with extLogin '{}' and extSourceName '{}'", + principal.getExtLogin(), principal.getExtSourceName()); + return perunAdapter.getPreauthenticatedUserId(principal); + } + + public static SAMLCredential getSamlCredential(HttpServletRequest request) { + ExpiringUsernameAuthenticationToken p = (ExpiringUsernameAuthenticationToken) request.getUserPrincipal(); + if (p == null) { + return null; + } + return (SAMLCredential) p.getCredentials(); + } + + public static PerunPrincipal getPerunPrincipal(SAMLCredential credential) { + String extLogin = credential.getAttributeAsString(SAML_EPUID); + String extSourceName = credential.getRemoteEntityID(); + return new PerunPrincipal(extLogin, extSourceName); + } + + /** + * Extract PerunPrincipal from request + * @param req request object + * @param proxyExtSourceName name of proxy + * @return extracted principal or null if not present + */ + public static PerunPrincipal extractPerunPrincipal(HttpServletRequest req, String proxyExtSourceName) { + String extLogin = null; + String remoteUser = req.getRemoteUser(); + if (isNotEmpty(remoteUser)) { + extLogin = remoteUser; + } else if (req.getUserPrincipal() != null) { + extLogin = ((User)req.getUserPrincipal()).getUsername(); + } + + PerunPrincipal principal = null; + log.error("{}", req.getUserPrincipal()); + log.error("{}", req.getRemoteUser()); + + + if (extLogin != null) { + principal = new PerunPrincipal(extLogin, proxyExtSourceName); + log.debug("extracted principal '{}'", principal); + } else { + log.debug("could not extract principal"); + } + + return principal; + } + + /** + * Check if given scope has been requested + * @param scopeParam Value of parameter "scope" from request + * @param scope Name of scope to be found. + * @return TRUE if present, false otherwise + */ + public static boolean isScopePresent(String scopeParam, String scope) { + if (scopeParam == null || scopeParam.trim().isEmpty()) { + log.trace("no scope has been requested"); + return false; + } + + String[] scopes = scopeParam.split(" "); + for (String s : scopes) { + if (s.equals(scope)) { + log.trace("scope '{}' has been requested", scope); + return true; + } + } + log.trace("scope has not been requested"); + return false; + } + + /** + * Build URL of original request, remove forceAuthn parameter. + * @param req request wrapper object + * @return Rebuilt URL. + */ + public static String buildRequestURL(HttpServletRequest req) { + return buildRequestURL(req, null); + } + + /** + * Build URL of original request, remove forceAuthn parameter, add new parameters if passed. + * @param req request wrapper object + * @param additionalParams parameters to be added + * @return Rebuilt URL. + */ + public static String buildRequestURL(HttpServletRequest req, Map<String, String> additionalParams) { + String returnURL = req.getRequestURL().toString(); + + if (req.getQueryString() != null) { + if (req.getQueryString().contains(PARAM_FORCE_AUTHN)) { + String queryStr = removeForceAuthParam(req.getQueryString()); + returnURL += ('?' + queryStr); + } else { + returnURL += ('?' + req.getQueryString()); + } + + if (additionalParams != null) { + returnURL += ('&' + additionalParams.entrySet().stream() + .map(pair -> pair.getKey() + '=' + pair.getValue()) + .collect(Collectors.joining("&"))); + } + } + log.debug("returning rebuilt request URL: '{}'", returnURL); + return returnURL; + } + + /** + * Redirect user to the unapproved page. + * @param request original request object + * @param response response object + * @param clientId identifier of the service + */ + public static void redirectUnapproved(HttpServletRequest request, HttpServletResponse response, String clientId, String redirectMapping) + { + // cannot register, redirect to unapproved + Map<String, String> params = new HashMap<>(); + if (clientId != null) { + params.put("client_id", clientId); + } + + String redirectUrl = ControllerUtils.createRedirectUrl(request, PerunFilterConstants.AUTHORIZE_REQ_PATTERN, + redirectMapping, params); + response.reset(); + response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + response.setHeader("Location", redirectUrl); + } + + /** + * Redirect user to the correct page when cannot access the service based on membership. + * @param request Request object + * @param response Response object + * @param facility Facility representing the client + * @param user User accessing the service + * @param clientIdentifier ClientID + * @param facilityAttrsConfig Config object for facility attributes + * @param facilityAttributes Actual facility attributes + * @param perunAdapter Adapter to call Perun + */ + public static void redirectUserCannotAccess(HttpServletRequest request, + HttpServletResponse response, + Facility facility, + PerunUser user, + String clientIdentifier, + FacilityAttrsConfig facilityAttrsConfig, + Map<String, PerunAttributeValue> facilityAttributes, + PerunAdapter perunAdapter, + String redirectUrl) + { + if (facilityAttributes.get(facilityAttrsConfig.getAllowRegistrationAttr()).valueAsBoolean()) { + boolean canRegister = perunAdapter.getAdapterRpc().groupWhereCanRegisterExists(facility); + if (canRegister) { + PerunAttributeValue customRegUrlAttr = facilityAttributes.get(facilityAttrsConfig.getRegistrationURLAttr()); + if (customRegUrlAttr != null && customRegUrlAttr.valueAsString() != null) { + String customRegUrl = facilityAttributes.get(facilityAttrsConfig.getRegistrationURLAttr()).valueAsString(); + customRegUrl = validateUrl(customRegUrl); + if (customRegUrl != null) { + // redirect to custom registration URL + FiltersUtils.redirectToCustomRegUrl(response, customRegUrl, user); + return; + } + } + + if (facilityAttributes.get(facilityAttrsConfig.getDynamicRegistrationAttr()).valueAsBoolean()) { + // redirect to registration form + FiltersUtils.redirectToRegistrationForm(request, response, clientIdentifier, facility, user); + return; + } + } + } + + // cannot register, redirect to unapproved + log.debug("user cannot register to obtain access, redirecting user '{}' to unapproved page", user); + FiltersUtils.redirectUnapproved(request, response, clientIdentifier, redirectUrl); + } + + private static void redirectToRegistrationForm(HttpServletRequest request, HttpServletResponse response, + String clientIdentifier, Facility facility, PerunUser user) { + Map<String, String> params = new HashMap<>(); + params.put("client_id", clientIdentifier); + params.put("facility_id", facility.getId().toString()); + params.put("user_id", String.valueOf(user.getId())); + String redirectUrl = ControllerUtils.createRedirectUrl(request, PerunFilterConstants.AUTHORIZE_REQ_PATTERN, + PerunUnapprovedRegistrationController.REGISTRATION_CONTINUE_MAPPING, params); + log.debug("redirecting user '{}' to the registration form URL: {}", user, redirectUrl); + response.reset(); + response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + response.setHeader("Location", redirectUrl); + } + + private static void redirectToCustomRegUrl(HttpServletResponse response, String customRegUrl, PerunUser user) { + log.debug("redirecting user '{}' to the custom registration URL: {}", user, customRegUrl); + response.reset(); + response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + response.setHeader("Location", customRegUrl); + } + + private static String validateUrl(String customRegUrl) { + return (customRegUrl == null || customRegUrl.isEmpty()) ? null : customRegUrl; + } + + private static String removeForceAuthParam(String query) { + return Arrays.stream(query.split("&")) + .map(FiltersUtils::splitQueryParameter) + .filter(pair -> !PARAM_FORCE_AUTHN.equals(pair.getKey())) + .map(pair -> pair.getKey() + "=" + pair.getValue()) + .collect(Collectors.joining("&")); + } + + private static Map.Entry<String, String> splitQueryParameter(String it) { + final int idx = it.indexOf("="); + final String key = (idx > 0) ? it.substring(0, idx) : it; + final String value = (idx > 0 && it.length() > idx + 1) ? it.substring(idx + 1) : ""; + return new AbstractMap.SimpleImmutableEntry<>(key, value); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunFilterConstants.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunFilterConstants.java new file mode 100644 index 000000000..12401bb48 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunFilterConstants.java @@ -0,0 +1,40 @@ +package cz.muni.ics.oidc.server.filters; + +/** + * Class containing common constants used by Perun request filters. + * + * @author Dominik Baranek <baranek@ics.muni.cz> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class PerunFilterConstants { + + public static final String AUTHORIZE_REQ_PATTERN = "/authorize"; + public static final String SHIB_IDENTITY_PROVIDER = "Shib-Identity-Provider"; + public static final String SHIB_AUTHN_CONTEXT_CLASS = "Shib-AuthnContext-Class"; + public static final String SHIB_AUTHN_CONTEXT_METHOD = "Shib-Authentication-Method"; + + public static final String PARAM_CLIENT_ID = "client_id"; + public static final String PARAM_SCOPE = "scope"; + public static final String PARAM_MESSAGE = "message"; + public static final String PARAM_HEADER = "header"; + public static final String PARAM_TARGET = "target"; + public static final String PARAM_FORCE_AUTHN = "forceAuthn"; + public static final String PARAM_PROMPT = "prompt"; + public static final String PARAM_REASON = "reason"; + public static final String PARAM_ACCEPTED = "accepted"; + public static final String PARAM_ACR_VALUES = "acr_values"; + public static final String PARAM_POST_LOGOUT_REDIRECT_URI = "post_logout_redirect_uri"; + public static final String PARAM_STATE = "state"; + public static final String CLIENT_ID_PREFIX = "urn:cesnet:proxyidp:client_id:"; + public static final String AARC_IDP_HINT = "aarc_idp_hint"; + + public static final String IDP_ENTITY_ID_PREFIX = "urn:cesnet:proxyidp:idpentityid:"; + public static final String FILTER_PREFIX = "urn:cesnet:proxyidp:filter:"; + public static final String EFILTER_PREFIX = "urn:cesnet:proxyidp:efilter:"; + + public static final String SAML_EPUID = "urn:oid:1.3.6.1.4.1.5923.1.1.1.13"; + public static final String REFEDS_MFA = "https://refeds.org/profile/mfa"; + public static final String PROMPT_LOGIN = "login"; + public static final String PROMPT_SELECT_ACCOUNT = "select_account"; + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunFiltersContext.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunFiltersContext.java new file mode 100644 index 000000000..0dda78f45 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunFiltersContext.java @@ -0,0 +1,93 @@ +package cz.muni.ics.oidc.server.filters; + +import cz.muni.ics.oidc.BeanUtil; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +/** + * Class that contains all custom Perun request filters. Filters are stored in the LinkedList + * and executed in the order they are added to the list. + * + * Filters are configured from configuration file in following way: + * filter.names=filterName1,filterName2,... + * + * @see PerunRequestFilter for configuration of filter + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class PerunFiltersContext { + + private static final Logger log = LoggerFactory.getLogger(PerunFiltersContext.class); + + private static final String FILTER_NAMES = "filter.names"; + private static final String FILTER_CLASS = ".class"; + private static final String PREFIX = "filter."; + + private List<PerunRequestFilter> filters; + private Properties properties; + private BeanUtil beanUtil; + + public PerunFiltersContext(Properties properties, BeanUtil beanUtil) { + this.properties = properties; + this.beanUtil = beanUtil; + this.filters = new LinkedList<>(); + + String filterNames = properties.getProperty(FILTER_NAMES); + log.debug("Filters to be initialized '{}'", filterNames); + + log.debug("--------------------------------"); + for (String filterName: filterNames.split(",")) { + PerunRequestFilter requestFilter = loadFilter(filterName); + filters.add(requestFilter); + log.debug("--------------------------------"); + } + } + + public List<PerunRequestFilter> getFilters() { + return filters; + } + + private PerunRequestFilter loadFilter(String filterName) { + String propPrefix = PerunFiltersContext.PREFIX + filterName; + String filterClass = properties.getProperty(propPrefix + FILTER_CLASS, null); + if (!StringUtils.hasText(filterClass)) { + log.warn("{} - failed to initialized filter: no class has ben configured", filterName); + return null; + } + log.trace("{} - loading class '{}'", filterName, filterClass); + + try { + Class<?> rawClazz = Class.forName(filterClass); + if (!PerunRequestFilter.class.isAssignableFrom(rawClazz)) { + log.warn("{} - failed to initialized filter: class '{}' does not extend PerunRequestFilter", + filterName, filterClass); + return null; + } + + @SuppressWarnings("unchecked") Class<PerunRequestFilter> clazz = (Class<PerunRequestFilter>) rawClazz; + Constructor<PerunRequestFilter> constructor = clazz.getConstructor(PerunRequestFilterParams.class); + PerunRequestFilterParams params = new PerunRequestFilterParams(filterName, propPrefix, properties, beanUtil); + return constructor.newInstance(params); + } catch (ClassNotFoundException e) { + log.warn("{} - failed to initialize filter: class '{}' was not found", filterName, filterClass); + log.trace("{} - details:", filterName, e); + return null; + } catch (NoSuchMethodException e) { + log.warn("{} - failed to initialize filter: class '{}' does not have proper constructor", + filterName, filterClass); + log.trace("{} - details:", filterName, e); + return null; + } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + log.warn("{} - failed to initialize filter: class '{}' cannot be instantiated", filterName, filterClass); + log.trace("{} - details:", filterName, e); + return null; + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunRequestFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunRequestFilter.java new file mode 100644 index 000000000..c8282fe3b --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunRequestFilter.java @@ -0,0 +1,110 @@ +package cz.muni.ics.oidc.server.filters; + +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.AUTHORIZE_REQ_PATTERN; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; + +/** + * Abstract class for Perun filters. All filters called in CallPerunFiltersFilter has to extend this. + * + * Configuration of filter names: + * <ul> + * <li><b>filter.names</b> - comma separated list of names of the request filters</li> + * </ul> + * + * Configuration of filter (replace [name] part with the name defined for the filter): + * <ul> + * <li><b>filter.[name].class</b> - Class the filter instantiates</li> + * <li><b>filter.[name].subs</b> - comma separated list of sub values for which execution of filter will be skipped + * if user's SUB is in the list</li> + * <li><b>filter.[name].clientIds</b> - comma separated list of client_id values for which execution of filter + * will be skipped if client_id is in the list</li> + * </ul> + * + * @see cz.muni.ics.oidc.server.filters.impl package for specific filters and their configuration + * + * @author Dominik Baranek <baranek@ics.muni.cz> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public abstract class PerunRequestFilter { + + private static final Logger log = LoggerFactory.getLogger(PerunRequestFilter.class); + + private static final String DELIMITER = ","; + private static final String CLIENT_IDS = "clientIds"; + private static final String SUBS = "subs"; + + private static final RequestMatcher requestMatcher = new AntPathRequestMatcher(AUTHORIZE_REQ_PATTERN); + + private final String filterName; + private Set<String> clientIds = new HashSet<>(); + private Set<String> subs = new HashSet<>(); + + public PerunRequestFilter(PerunRequestFilterParams params) { + filterName = params.getFilterName(); + + if (params.hasProperty(CLIENT_IDS)) { + this.clientIds = new HashSet<>(Arrays.asList(params.getProperty(CLIENT_IDS).split(DELIMITER))); + } + + if (params.hasProperty(SUBS)) { + this.subs = new HashSet<>(Arrays.asList(params.getProperty(SUBS).split(DELIMITER))); + } + + log.debug("{} - filter initialized", filterName); + log.debug("{} - skip execution for users with SUB in: {}", filterName, subs); + log.debug("{} - skip execution for clients with CLIENT_ID in: {}", filterName, clientIds); + } + + /** + * In this method is done whole logic of filer + * + * @param request request + * @param response response + * @return boolean if filter was successfully done + * @throws IOException this exception could be thrown because of failed or interrupted I/O operation + */ + protected abstract boolean process(ServletRequest request, ServletResponse response, FilterParams params) + throws IOException; + + public boolean doFilter(ServletRequest req, ServletResponse res, FilterParams params) throws IOException { + HttpServletRequest request = (HttpServletRequest) req; + // skip everything that's not an authorize URL + if (!requestMatcher.matches(request)) { + log.debug("{} - filter has been skipped, did not match '/authorize' the request", filterName); + return true; + } + if (!skip(request)) { + log.trace("{} - executing filter", filterName); + return this.process(req, res, params); + } else { + return true; + } + } + + private boolean skip(HttpServletRequest request) { + String sub = (request.getUserPrincipal() != null) ? request.getUserPrincipal().getName() : null; + String clientId = request.getParameter(PerunFilterConstants.PARAM_CLIENT_ID); + + if (sub != null && subs.contains(sub)) { + log.debug("{} - skip filter execution: matched one of the ignored SUBS ({})", filterName, sub); + return true; + } else if (clientId != null && clientIds.contains(clientId)){ + log.debug("{} - skip filter execution: matched one of the ignored CLIENT_IDS ({})", filterName, clientId); + return true; + } + + return false; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunRequestFilterParams.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunRequestFilterParams.java new file mode 100644 index 000000000..10119b4bc --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunRequestFilterParams.java @@ -0,0 +1,45 @@ +package cz.muni.ics.oidc.server.filters; + +import cz.muni.ics.oidc.BeanUtil; +import java.util.Properties; + +/** + * Class holding parameters for filter instantiation + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class PerunRequestFilterParams { + + private String filterName; + + private String propertyPrefix; + private Properties properties; + private BeanUtil beanUtil; + + public PerunRequestFilterParams(String filterName, String propertyPrefix, Properties properties, BeanUtil beanUtil) { + this.filterName = filterName; + this.propertyPrefix = propertyPrefix; + this.properties = properties; + this.beanUtil = beanUtil; + } + + public boolean hasProperty(String name) { + return this.properties.containsKey(propertyPrefix + '.' + name); + } + + public String getProperty(String name) { + return this.properties.getProperty(propertyPrefix + '.' + name); + } + + public BeanUtil getBeanUtil() { + return beanUtil; + } + + public String getFilterName() { + return filterName; + } + + public Properties getProperties() { + return properties; + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/MultiMDCFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/MultiMDCFilter.java new file mode 100644 index 000000000..e4980c8ee --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/MultiMDCFilter.java @@ -0,0 +1,33 @@ +package cz.muni.ics.oidc.server.filters.impl; + +import cz.muni.ics.oidc.server.filters.impl.mdc.RemoteAddressMDCFilter; +import cz.muni.ics.oidc.server.filters.impl.mdc.SessionIdMDCFilter; +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import org.slf4j.MDC; +import org.springframework.web.filter.GenericFilterBean; + +public class MultiMDCFilter extends GenericFilterBean { + + private final RemoteAddressMDCFilter remoteAddressMDCFilter; + private final SessionIdMDCFilter sessionIdMDCFilter; + + public MultiMDCFilter() { + this.remoteAddressMDCFilter = new RemoteAddressMDCFilter(); + this.sessionIdMDCFilter = new SessionIdMDCFilter(); + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException + { + remoteAddressMDCFilter.doFilter(servletRequest); + sessionIdMDCFilter.doFilter(servletRequest); + filterChain.doFilter(servletRequest, servletResponse); + MDC.clear(); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunAuthorizationFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunAuthorizationFilter.java new file mode 100644 index 000000000..3f574f1e3 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunAuthorizationFilter.java @@ -0,0 +1,93 @@ +package cz.muni.ics.oidc.server.filters.impl; + +import cz.muni.ics.oidc.BeanUtil; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig; +import cz.muni.ics.oidc.server.filters.FilterParams; +import cz.muni.ics.oidc.server.filters.FiltersUtils; +import cz.muni.ics.oidc.server.filters.PerunRequestFilter; +import cz.muni.ics.oidc.server.filters.PerunRequestFilterParams; +import cz.muni.ics.oidc.web.controllers.PerunUnapprovedController; +import java.util.Map; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Authorization filter. Decides if user can access the service based on his/hers + * membership in the groups assigned to the Perun facility resources. Facility represents + * client in this context. + * + * Configuration: + * - based on the configuration of bean "facilityAttrsConfig" + * @see FacilityAttrsConfig + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class PerunAuthorizationFilter extends PerunRequestFilter { + + private static final Logger log = LoggerFactory.getLogger(PerunAuthorizationFilter.class); + + private final PerunAdapter perunAdapter; + private final FacilityAttrsConfig facilityAttrsConfig; + private final String filterName; + + public PerunAuthorizationFilter(PerunRequestFilterParams params) { + super(params); + BeanUtil beanUtil = params.getBeanUtil(); + this.perunAdapter = beanUtil.getBean(PerunAdapter.class); + this.facilityAttrsConfig = beanUtil.getBean(FacilityAttrsConfig.class); + this.filterName = params.getFilterName(); + } + + @Override + protected boolean process(ServletRequest req, ServletResponse res, FilterParams params) { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + + Facility facility = params.getFacility(); + if (facility == null || facility.getId() == null) { + log.debug("{} - skip filter execution: no facility provided", filterName); + return true; + } + + PerunUser user = params.getUser(); + if (user == null || user.getId() == null) { + log.debug("{} - skip filter execution: no user provided", filterName); + return true; + } + + return this.decideAccess(facility, user, request, response, params.getClientIdentifier(), + perunAdapter, facilityAttrsConfig); + } + + private boolean decideAccess(Facility facility, PerunUser user, HttpServletRequest request, + HttpServletResponse response, String clientIdentifier, PerunAdapter perunAdapter, + FacilityAttrsConfig facilityAttrsConfig) + { + Map<String, PerunAttributeValue> facilityAttributes = perunAdapter.getFacilityAttributeValues( + facility, facilityAttrsConfig.getMembershipAttrNames()); + + if (!facilityAttributes.get(facilityAttrsConfig.getCheckGroupMembershipAttr()).valueAsBoolean()) { + log.debug("{} - skip filter execution: membership check not requested", filterName); + return true; + } + + if (perunAdapter.canUserAccessBasedOnMembership(facility, user.getId())) { + log.info("{} - user allowed to access the service", filterName); + return true; + } else { + FiltersUtils.redirectUserCannotAccess(request, response, facility, user, clientIdentifier, + facilityAttrsConfig, facilityAttributes, perunAdapter, + PerunUnapprovedController.UNAPPROVED_AUTHORIZATION); + return false; + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunEnsureVoMember.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunEnsureVoMember.java new file mode 100644 index 000000000..0d027535f --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunEnsureVoMember.java @@ -0,0 +1,190 @@ +package cz.muni.ics.oidc.server.filters.impl; + +import cz.muni.ics.oidc.BeanUtil; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.server.filters.FilterParams; +import cz.muni.ics.oidc.server.filters.PerunRequestFilter; +import cz.muni.ics.oidc.server.filters.PerunRequestFilterParams; +import cz.muni.ics.oidc.web.controllers.ControllerUtils; +import cz.muni.ics.oidc.web.controllers.PerunUnapprovedController; +import cz.muni.ics.oidc.web.controllers.RegistrationController; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import org.apache.http.HttpHeaders; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +/** + * This filter forwards user to a warning page if the service is in test environment. + * Otherwise, user can to access the service. + * + * Configuration (replace [name] part with the name defined for the filter): + * <ul> + * <li><b>filter.[name].triggerAttr</b> - mapping to attribute which contains flag if this is enabled for facility</li> + * <li><b>filter.[name].voDefsAttr</b> - mapping to attribute which contains VO(s) to check</li> + * <li><b>filter.[name].loginURL</b> - mapping to the attribute containing service login URL</li> + * </ul> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class PerunEnsureVoMember extends PerunRequestFilter { + + private static final Logger log = LoggerFactory.getLogger(PerunEnsureVoMember.class); + + private static final String TRIGGER_ATTR = "triggerAttr"; + private static final String VO_DEFS_ATTR = "voDefsAttr"; + private static final String LOGIN_URL_ATTR = "loginURL"; + + private final String triggerAttr; + private final String voDefsAttr; + private final String loginUrlAttr; + private final PerunAdapter perunAdapter; + private final String filterName; + private final PerunOidcConfig perunOidcConfig; + + public PerunEnsureVoMember(PerunRequestFilterParams params) { + super(params); + BeanUtil beanUtil = params.getBeanUtil(); + this.perunOidcConfig = beanUtil.getBean(PerunOidcConfig.class); + this.perunAdapter = beanUtil.getBean(PerunAdapter.class); + this.filterName = params.getFilterName(); + this.triggerAttr = params.getProperty(TRIGGER_ATTR); + if (!StringUtils.hasText(triggerAttr)) { + throw new IllegalArgumentException("No value configured for '" + TRIGGER_ATTR + "' in filter " + filterName); + } + this.voDefsAttr = params.getProperty(VO_DEFS_ATTR); + if (!StringUtils.hasText(voDefsAttr)) { + throw new IllegalArgumentException("No value configured for '" + VO_DEFS_ATTR + "' in filter " + filterName); + } + this.loginUrlAttr = params.getProperty(LOGIN_URL_ATTR); + log.debug("{} - initialized filter: {}", filterName, this); + } + + @Override + protected boolean process(ServletRequest req, ServletResponse res, FilterParams params) throws IOException { + HttpServletResponse response = (HttpServletResponse) res; + + Facility facility = params.getFacility(); + if (facility == null || facility.getId() == null) { + log.debug("{} - skip execution: no facility provided", filterName); + return true; + } + + Map<String, PerunAttributeValue> attrs = perunAdapter.getFacilityAttributeValues(facility, + Arrays.asList(voDefsAttr, triggerAttr, loginUrlAttr)); + + PerunAttributeValue triggerAttrValue = attrs.getOrDefault(triggerAttr, null); + if (triggerAttrValue == null || !triggerAttrValue.valueAsBoolean()) { + log.debug("{} - skip execution: attribute '{}' is null or false, which disables the filter", + filterName, triggerAttr); + return true; + } + + PerunAttributeValue voDefsAttrValue = getVoDefsAttrValue(attrs.getOrDefault(voDefsAttr, null)); + if (voDefsAttrValue == null) { + log.debug("{} - skip execution: attribute '{}' has null or no value", filterName, voDefsAttr); + return true; + } + String voShortName = voDefsAttrValue.valueAsString(); + + boolean canAccess = perunAdapter.isUserInVo(params.getUser().getId(), voShortName); + + if (canAccess) { + log.debug("{} - user allowed to continue", filterName); + return true; + } else { + redirect(response, getLoginUrl(facility.getId()), voShortName); + return false; + } + } + + private void redirect(HttpServletResponse response, PerunAttributeValue loginUrlAttr, String voShortName) { + String loginUrl = null; + if (loginUrlAttr != null && StringUtils.hasText(loginUrlAttr.valueAsString())) { + loginUrl = loginUrlAttr.valueAsString(); + } + if (StringUtils.hasText(voShortName) && perunAdapter.getAdapterRpc().hasApplicationForm(voShortName)) { + redirectDirectly(response, loginUrl, voShortName); + } else { + redirectUnapproved(response); + } + } + + private PerunAttributeValue getLoginUrl(Long facilityId) { + if (loginUrlAttr != null) { + return perunAdapter.getFacilityAttributeValue(facilityId, loginUrlAttr); + } + return null; + } + + private PerunAttributeValue getVoDefsAttrValue(PerunAttributeValue attrValue) { + if (attrValue == null) { + return null; + } else if (attrValue.valueAsJson().isArray() && attrValue.valueAsJson().size() < 1) { + return null; + } + return attrValue; + } + + private boolean canAccess(PerunAttributeValue attrValue, Set<String> memberShortNames) { + if (attrValue.valueAsJson().isArray()) { + Set<String> val = attrValue.valueAsList() == null ? + Collections.emptySet() : new HashSet<>(attrValue.valueAsList()); + return !Collections.disjoint(val, memberShortNames); + } else { + String val = attrValue.valueAsString(); + return memberShortNames.contains(val); + } + } + + @Override + public String toString() { + return "PerunEnsureVoMember{" + + "voDefsAttr='" + voDefsAttr + '\'' + + ", loginUrlAttr='" + loginUrlAttr + '\'' + + '}'; + } + + private void redirectDirectly(HttpServletResponse res, String loginUrl, String voShortName) { + String registrarUrl = perunOidcConfig.getRegistrarUrl(); + Map<String, String> params = new HashMap<>(); + params.put("vo", voShortName); + if (StringUtils.hasText(loginUrl)) { + params.put("targetnew", loginUrl); + params.put("targetexisting", loginUrl); + } + String target = ControllerUtils.createUrl(registrarUrl, params); + + String url = ControllerUtils.constructRequestUrl(perunOidcConfig, RegistrationController.CONTINUE_DIRECT_MAPPING); + params.clear(); + params.put(RegistrationController.PARAM_TARGET, target); + + String redirectUrl = ControllerUtils.createUrl(url, params); + log.debug("{} - redirecting user to '{}'", filterName, redirectUrl); + res.reset(); + res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + res.setHeader(HttpHeaders.LOCATION, redirectUrl); + } + + private void redirectUnapproved(HttpServletResponse res) { + String redirectUrl = ControllerUtils.constructRequestUrl(perunOidcConfig, + PerunUnapprovedController.UNAPPROVED_ENSURE_VO_MAPPING); + + log.debug("{} - redirecting user to '{}'", filterName, redirectUrl); + res.reset(); + res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + res.setHeader(HttpHeaders.LOCATION, redirectUrl); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunForceAupFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunForceAupFilter.java new file mode 100644 index 000000000..ab62c0b85 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunForceAupFilter.java @@ -0,0 +1,323 @@ +package cz.muni.ics.oidc.server.filters.impl; + +import static cz.muni.ics.oidc.web.controllers.AupController.APPROVED; + +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.muni.ics.oidc.BeanUtil; +import cz.muni.ics.oidc.models.Aup; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.PerunAttribute; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.server.filters.FilterParams; +import cz.muni.ics.oidc.server.filters.FiltersUtils; +import cz.muni.ics.oidc.server.filters.PerunRequestFilter; +import cz.muni.ics.oidc.server.filters.PerunRequestFilterParams; +import cz.muni.ics.oidc.web.controllers.AupController; +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +/** + * AUP filter checks if there are new AUPs which user hasn't accepted yet and forces him to do that. + * + * Configuration (replace [name] part with the name defined for the filter): + * <ul> + * <li><b>filter.[name].orgAupsAttrName</b> - Mapping to Perun entityless attribute containing organization AUPs</li> + * <li><b>filter.[name].userAupsAttrName</b> - Mapping to Perun user attribute containing list of AUPS approved by user</li> + * <li><b>filter.[name].voAupAttrName</b> - Mapping to Perun VO attribute containing AUP specific for VO</li> + * <li><b>filter.[name].facilityRequestedAupsAttrName</b> - Mapping to Perun facility attribute containing list of AUPs requested + * by the service. Contains only keys for those AUPs</li> + * <li><b>filter.[name].voShortNamesAttrName</b> - Mapping to Perun facility attribute containing list of short names for VOs + * that have a resource assigned to the facility</li> + * </ul> + * + * @author Dominik Baranek <baranek@ics.muni.cz> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class PerunForceAupFilter extends PerunRequestFilter { + + private static final Logger log = LoggerFactory.getLogger(PerunForceAupFilter.class); + private static final String DATE_FORMAT = "yyyy-MM-dd"; + + /* CONFIGURATION PROPERTIES */ + private static final String ORG_AUPS_ATTR_NAME = "orgAupsAttrName"; + private static final String USER_AUPS_ATTR_NAME = "userAupsAttrName"; + private static final String VO_AUP_ATTR_NAME = "voAupAttrName"; + private static final String FACILITY_REQUESTED_AUPS_ATTR_NAME = "facilityRequestedAupsAttrName"; + private static final String VO_SHORT_NAMES_ATTR_NAME = "voShortNamesAttrName"; + + private final String perunOrgAupsAttrName; + private final String perunUserAupsAttrName; + private final String perunVoAupAttrName; + private final String perunFacilityRequestedAupsAttrName; + private final String perunFacilityVoShortNamesAttrName; + /* END OF CONFIGURATION PROPERTIES */ + + private final ObjectMapper mapper = new ObjectMapper(); + + private final PerunAdapter perunAdapter; + private final PerunOidcConfig perunOidcConfig; + private final String filterName; + + public PerunForceAupFilter(PerunRequestFilterParams params) { + super(params); + BeanUtil beanUtil = params.getBeanUtil(); + this.perunAdapter = beanUtil.getBean(PerunAdapter.class); + this.perunOidcConfig = beanUtil.getBean(PerunOidcConfig.class); + + this.perunOrgAupsAttrName = params.getProperty(ORG_AUPS_ATTR_NAME); + this.perunUserAupsAttrName = params.getProperty(USER_AUPS_ATTR_NAME); + this.perunVoAupAttrName = params.getProperty(VO_AUP_ATTR_NAME); + this.perunFacilityRequestedAupsAttrName = params.getProperty(FACILITY_REQUESTED_AUPS_ATTR_NAME); + this.perunFacilityVoShortNamesAttrName = params.getProperty(VO_SHORT_NAMES_ATTR_NAME); + this.filterName = params.getFilterName(); + } + + @Override + protected boolean process(ServletRequest req, ServletResponse res, FilterParams params) throws IOException { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + + if (request.getSession() != null && request.getSession().getAttribute(APPROVED) != null) { + request.getSession().removeAttribute(APPROVED); + log.debug("{} - skip filter execution: aups are already approved, check at next access to the service due" + + " to a delayed propagation to LDAP", filterName); + return true; + } + + PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter); + if (user == null || user.getId() == null) { + log.debug("{} - skip filter execution: no user provider", filterName); + return true; + } + + Facility facility = params.getFacility(); + if (facility == null || facility.getId() == null) { + log.debug("{} - skip filter execution: no facility provider", filterName); + return true; + } + + List<String> attrsToFetch = new ArrayList<>( + Arrays.asList(perunFacilityRequestedAupsAttrName, perunFacilityVoShortNamesAttrName)); + Map<String, PerunAttributeValue> facilityAttributes = perunAdapter.getFacilityAttributeValues(facility, attrsToFetch); + + if (facilityAttributes == null) { + log.debug("{} - skip filter execution: could not fetch attributes '{}' for facility '{}'", + filterName, attrsToFetch, facility); + return true; + } else if (!facilityAttributes.containsKey(perunFacilityRequestedAupsAttrName) && + !facilityAttributes.containsKey(perunFacilityVoShortNamesAttrName)) + { + log.debug("{} - skip filter execution: could not fetch required attributes '{}' and '{}' for facility '{}'", + filterName, perunFacilityRequestedAupsAttrName, perunFacilityVoShortNamesAttrName, facility); + return true; + } + + Map<String, Aup> newAups; + + try { + newAups = getAupsToApprove(user, facilityAttributes); + } catch (ParseException | IOException e) { + log.warn("{} - caught parse exception when processing AUPs to approve", filterName); + log.trace("{} - details:", filterName, e); + return true; + } + + if (!newAups.isEmpty()) { + log.debug("{} - user has to approve some AUPs", filterName); + log.trace("{} - AUPS to be approved: '{}'", filterName, newAups); + String newAupsString = mapper.writeValueAsString(newAups); + + request.getSession().setAttribute(AupController.RETURN_URL, request.getRequestURI() + .replace(request.getContextPath(), "") + '?' + request.getQueryString()); + request.getSession().setAttribute(AupController.NEW_AUPS, newAupsString); + request.getSession().setAttribute(AupController.USER_ATTR, perunUserAupsAttrName); + + log.debug("{} - redirecting user '{}' to AUPs approval page", filterName, user); + response.sendRedirect(request.getContextPath() + '/' + AupController.URL); + return false; + } + + log.debug("{} - no need to approve any AUPs", filterName); + return true; + } + + private Map<String, Aup> getAupsToApprove(PerunUser user, Map<String, PerunAttributeValue> facilityAttributes) + throws ParseException, IOException + { + Map<String, Aup> aupsToApprove= new LinkedHashMap<>(); + + PerunAttributeValue userAupsAttr = perunAdapter.getUserAttributeValue(user.getId(), perunUserAupsAttrName); + if (perunOidcConfig.isFillMissingUserAttrs() && (userAupsAttr == null || userAupsAttr.isNullValue())) { + userAupsAttr = perunAdapter.getAdapterFallback().getUserAttributeValue(user.getId(), perunUserAupsAttrName); + } + Map<String, List<Aup>> userAups = convertToMapKeyToListOfAups(userAupsAttr.valueAsMap()); + + PerunAttributeValue requestedAupsAttr = facilityAttributes.get(perunFacilityRequestedAupsAttrName); + PerunAttributeValue facilityVoShortNamesAttr = facilityAttributes.get(perunFacilityVoShortNamesAttrName); + + if (requestedAupsAttr != null && !requestedAupsAttr.isNullValue() && requestedAupsAttr.valueAsList() != null + && !requestedAupsAttr.valueAsList().isEmpty()) { + Map<String, Aup> orgAupsToApprove = getOrgAupsToApprove(requestedAupsAttr.valueAsList(), userAups); + mergeAupMaps(aupsToApprove, orgAupsToApprove); + } + + if (facilityVoShortNamesAttr != null && !facilityVoShortNamesAttr.isNullValue() + && facilityVoShortNamesAttr.valueAsList() != null && !facilityVoShortNamesAttr.valueAsList().isEmpty()) { + Map<String, Aup> voAupsToApprove = getVoAupsToApprove(facilityVoShortNamesAttr.valueAsList(), userAups); + mergeAupMaps(aupsToApprove, voAupsToApprove); + } + + return aupsToApprove; + } + + private void mergeAupMaps(Map<String, Aup> original, Map<String, Aup> updates) { + for (Map.Entry<String, Aup> pair: updates.entrySet()) { + if (original.containsKey(pair.getKey())) { + Aup originalAup = original.get(pair.getKey()); + Aup updateAup = pair.getValue(); + if (updateAup.getDateAsLocalDate().isAfter(originalAup.getDateAsLocalDate())) { + original.replace(pair.getKey(), pair.getValue()); + } + } else { + original.put(pair.getKey(), pair.getValue()); + } + } + } + + private Map<String, Aup> getVoAupsToApprove(List<String> facilityVoShortNames, Map<String, List<Aup>> userAups) + throws IOException, ParseException { + Map<String, Aup> aupsToApprove = new LinkedHashMap<>(); + Map<String, List<Aup>> voAups = getVoAups(facilityVoShortNames); + + if (!voAups.isEmpty()) { + for (Map.Entry<String, List<Aup>> keyToVoAup : voAups.entrySet()) { + Aup voLatestAup = getLatestAupFromList(keyToVoAup.getValue()); + if (userAups.containsKey(keyToVoAup.getKey())) { + Aup userLatestAup = getLatestAupFromList(userAups.get(keyToVoAup.getKey())); + if (! (voLatestAup.getDateAsLocalDate().isAfter(userLatestAup.getDateAsLocalDate()))) { + continue; + } + } + log.debug("{} - need to approve AUP with key '{}' ({})", filterName, keyToVoAup.getKey(), voLatestAup); + aupsToApprove.put(keyToVoAup.getKey(), voLatestAup); + } + } + + log.trace("{} - VO AUPs to approve: {}", filterName, aupsToApprove); + return aupsToApprove; + } + + private Map<String, Aup> getOrgAupsToApprove(List<String > requestedAups, Map<String, List<Aup>> userAups) + throws ParseException, IOException + { + Map<String, Aup> aupsToApprove = new LinkedHashMap<>(); + Map<String, List<Aup>> orgAups = new HashMap<>(); + + Map<String, PerunAttribute> orgAupsAttr = perunAdapter.getAdapterRpc() + .getEntitylessAttributes(perunOrgAupsAttrName); + + if (orgAupsAttr != null && !orgAupsAttr.isEmpty()) { + for (Map.Entry<String, PerunAttribute> entry : orgAupsAttr.entrySet()) { + if (entry.getValue() != null && entry.getValue().valueAsString() != null) { + List<Aup> aups = Arrays.asList(mapper.readValue(entry.getValue().valueAsString(), Aup[].class)); + orgAups.put(entry.getKey(), aups); + } + } + } + log.debug("{} - Mapped ORG aups: {}", filterName, orgAups); + + if (!orgAups.isEmpty()) { + for (String requiredOrgAupKey : requestedAups) { + if (!orgAups.containsKey(requiredOrgAupKey) || orgAups.get(requiredOrgAupKey) == null) { + continue; + } + Aup orgLatestAup = getLatestAupFromList(orgAups.get(requiredOrgAupKey)); + if (userAups.containsKey(requiredOrgAupKey)) { + Aup userLatestAup = getLatestAupFromList(userAups.get(requiredOrgAupKey)); + if (!(orgLatestAup.getDateAsLocalDate().isAfter(userLatestAup.getDateAsLocalDate()))) { + continue; + } + } + log.debug("{} - need to approve AUP with key '{}' ({})", filterName, requiredOrgAupKey, orgLatestAup); + aupsToApprove.put(requiredOrgAupKey, orgLatestAup); + } + } + + log.debug("{} - ORG AUPs to approve: {}", filterName, aupsToApprove); + return aupsToApprove; + } + + private Map<String, List<Aup>> getVoAups(List<String> voShortNames) throws IOException { + Map<String, List<Aup>> voAups = new HashMap<>(); + + if (voShortNames != null && !voShortNames.isEmpty()) { + for (String voShortName : voShortNames) { + Long voId = perunAdapter.getVoByShortName(voShortName).getId(); + + PerunAttributeValue voAupAttr = perunAdapter.getVoAttributeValue(voId, perunVoAupAttrName); + if (voAupAttr == null || voAupAttr.valueAsString() == null) { + continue; + } + + if (StringUtils.hasText(voAupAttr.valueAsString())) { + List<Aup> aups = Arrays.asList(mapper.readValue(voAupAttr.valueAsString(), Aup[].class)); + if (!aups.isEmpty()) { + voAups.put(voShortName, aups); + } + } + } + } + + return voAups; + } + + private Map<String, List<Aup>> convertToMapKeyToListOfAups(Map<String, String> keyToListOfAupsString) + throws IOException + { + Map<String, List<Aup>> resultMap = new HashMap<>(); + if (keyToListOfAupsString != null && !keyToListOfAupsString.isEmpty()) { + for (Map.Entry<String, String> entry : keyToListOfAupsString.entrySet()) { + List<Aup> aups = Arrays.asList(mapper.readValue(entry.getValue(), Aup[].class)); + resultMap.put(entry.getKey(), aups); + } + } + return resultMap; + } + + private Aup getLatestAupFromList(List<Aup> aups) throws ParseException { + Aup latestAup = aups.get(0); + + for (Aup aup : aups) { + Date latestAupDate = new SimpleDateFormat(DATE_FORMAT).parse(latestAup.getDate()); + Date aupDate = new SimpleDateFormat(DATE_FORMAT).parse(aup.getDate()); + log.info("latestAupDate({}): {}", latestAup, latestAupDate); + log.info("aupDate({}): {}", aup, aupDate); + if (latestAupDate.before(aupDate)) { + log.info("before"); + latestAup = aup; + } + } + + log.info("latestAup: {}", latestAup); + return latestAup; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsCesnetEligibleFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsCesnetEligibleFilter.java new file mode 100644 index 000000000..6dc0a68da --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsCesnetEligibleFilter.java @@ -0,0 +1,145 @@ +package cz.muni.ics.oidc.server.filters.impl; + +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_FORCE_AUTHN; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_REASON; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_SCOPE; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_TARGET; +import static cz.muni.ics.oidc.web.controllers.PerunUnapprovedController.REASON_EXPIRED; +import static cz.muni.ics.oidc.web.controllers.PerunUnapprovedController.REASON_NOT_SET; + +import cz.muni.ics.oidc.BeanUtil; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.filters.FilterParams; +import cz.muni.ics.oidc.server.filters.FiltersUtils; +import cz.muni.ics.oidc.server.filters.PerunFilterConstants; +import cz.muni.ics.oidc.server.filters.PerunRequestFilter; +import cz.muni.ics.oidc.server.filters.PerunRequestFilterParams; +import cz.muni.ics.oidc.web.controllers.ControllerUtils; +import cz.muni.ics.oidc.web.controllers.PerunUnapprovedController; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.http.HttpHeaders; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This filter verifies that user attribute isCesnetEligible is not older than given time frame. + * In case the value is older, denies access to the service and forces user to use verified identity. + * Otherwise, user can to access the service. + * + * Configuration (replace [name] part with the name defined for the filter): + * <ul> + * <li><b>filter.[name].isCesnetEligibleAttr</b> - mapping to isCesnetEligible attribute</li> + * <li><b>filter.[name].validityPeriod</b> - specify in months, how long the value can be old, if no value + * or invalid value has been provided, defaults to 12 months</li> + * </ul> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class PerunIsCesnetEligibleFilter extends PerunRequestFilter { + + private static final Logger log = LoggerFactory.getLogger(PerunIsCesnetEligibleFilter.class); + + /* CONFIGURATION PROPERTIES */ + private static final String IS_CESNET_ELIGIBLE_ATTR_NAME = "isCesnetEligibleAttr"; + private static final String IS_CESNET_ELIGIBLE_SCOPE = "isCesnetEligibleScope"; + private static final String VALIDITY_PERIOD = "validityPeriod"; + private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + private final String isCesnetEligibleAttrName; + private final String triggerScope; + private final int validityPeriod; + /* END OF CONFIGURATION PROPERTIES */ + + private final PerunAdapter perunAdapter; + private final String filterName; + + public PerunIsCesnetEligibleFilter(PerunRequestFilterParams params) { + super(params); + BeanUtil beanUtil = params.getBeanUtil(); + this.perunAdapter = beanUtil.getBean(PerunAdapter.class); + this.isCesnetEligibleAttrName = params.getProperty(IS_CESNET_ELIGIBLE_ATTR_NAME); + this.triggerScope = params.getProperty(IS_CESNET_ELIGIBLE_SCOPE); + int validityPeriodParam = 12; + if (params.hasProperty(VALIDITY_PERIOD)) { + try { + validityPeriodParam = Integer.parseInt(params.getProperty(VALIDITY_PERIOD)); + } catch (NumberFormatException ignored) { + //no problem, we have default value + } + } + + this.validityPeriod = validityPeriodParam; + this.filterName = params.getFilterName(); + } + + @Override + protected boolean process(ServletRequest req, ServletResponse res, FilterParams params) { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + + if (!FiltersUtils.isScopePresent(request.getParameter(PARAM_SCOPE), triggerScope)) { + log.debug("{} - skip execution: scope '{}' is not present in request", filterName, triggerScope); + return true; + } + + PerunUser user = params.getUser(); + if (user == null || user.getId() == null) { + log.debug("{} - skip execution: no user provider", filterName); + return true; + } + + String reason = REASON_NOT_SET; + PerunAttributeValue attrValue = perunAdapter.getUserAttributeValue(user.getId(), isCesnetEligibleAttrName); + if (attrValue != null) { + LocalDateTime timeStamp; + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT); + timeStamp = LocalDateTime.parse(attrValue.valueAsString(), formatter); + } catch (DateTimeParseException e) { + log.warn("{} - could not parse timestamp from attribute '{}' value: '{}'", + filterName, isCesnetEligibleAttrName, attrValue.valueAsString()); + log.debug("{} - skip execution: no timestamp to compare to", filterName); + log.trace("{} - details:", filterName, e); + return true; + } + + LocalDateTime now = LocalDateTime.now(); + if (now.minusMonths(validityPeriod).isBefore(timeStamp)) { + log.debug("{} - attribute '{}' value is valid", filterName, isCesnetEligibleAttrName); + return true; + } else { + reason = REASON_EXPIRED; + } + } + + log.debug("{} - attribute '{}' value is invalid, stop user at this point", filterName, attrValue); + this.redirect(request, response, reason); + return false; + } + + private void redirect(HttpServletRequest req, HttpServletResponse res, String reason) { + Map<String, String> params = new HashMap<>(); + + String targetURL = FiltersUtils.buildRequestURL(req, Collections.singletonMap(PARAM_FORCE_AUTHN, "true")); + params.put(PARAM_TARGET, targetURL); + params.put(PARAM_REASON, reason); + + String redirectUrl = ControllerUtils.createRedirectUrl(req, PerunFilterConstants.AUTHORIZE_REQ_PATTERN, + PerunUnapprovedController.UNAPPROVED_IS_CESNET_ELIGIBLE_MAPPING, params); + log.debug("{} - redirecting user to unapproved: URL '{}'", filterName, redirectUrl); + res.reset(); + res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + res.setHeader(HttpHeaders.LOCATION, redirectUrl); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsTestSpFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsTestSpFilter.java new file mode 100644 index 000000000..f7af2146b --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsTestSpFilter.java @@ -0,0 +1,108 @@ +package cz.muni.ics.oidc.server.filters.impl; + +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_TARGET; +import static cz.muni.ics.oidc.web.controllers.IsTestSpController.IS_TEST_SP_APPROVED_SESS; + +import cz.muni.ics.oidc.BeanUtil; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.filters.FilterParams; +import cz.muni.ics.oidc.server.filters.FiltersUtils; +import cz.muni.ics.oidc.server.filters.PerunFilterConstants; +import cz.muni.ics.oidc.server.filters.PerunRequestFilter; +import cz.muni.ics.oidc.server.filters.PerunRequestFilterParams; +import cz.muni.ics.oidc.web.controllers.ControllerUtils; +import cz.muni.ics.oidc.web.controllers.IsTestSpController; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.http.HttpHeaders; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This filter forwards user to a warning page if the service is in test environment. + * Otherwise, user can to access the service. + * + * Configuration (replace [name] part with the name defined for the filter): + * <ul> + * <li><b>filter.[name].isTestSpAttr</b> - mapping to isCesnetEligible attribute</li> + * </ul> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + * @author Pavol Pluta <500348@mail.muni.cz> + */ +public class PerunIsTestSpFilter extends PerunRequestFilter { + + private static final Logger log = LoggerFactory.getLogger(PerunIsTestSpFilter.class); + + private static final String IS_TEST_SP_ATTR_NAME = "isTestSpAttr"; + + private final String isTestSpAttrName; + private final PerunAdapter perunAdapter; + private final String filterName; + + public PerunIsTestSpFilter(PerunRequestFilterParams params) { + super(params); + BeanUtil beanUtil = params.getBeanUtil(); + this.perunAdapter = beanUtil.getBean(PerunAdapter.class); + this.isTestSpAttrName = params.getProperty(IS_TEST_SP_ATTR_NAME); + this.filterName = params.getFilterName(); + } + + @Override + protected boolean process(ServletRequest req, ServletResponse res, FilterParams params) throws IOException { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + Facility facility = params.getFacility(); + if (facility == null || facility.getId() == null) { + log.debug("{} - skip execution: no facility provided", filterName); + return true; + } else if (testSpWarningApproved(request)){ + log.debug("{} - skip execution: warning already approved", filterName); + return true; + } + + PerunAttributeValue attrValue = perunAdapter.getFacilityAttributeValue(facility.getId(), isTestSpAttrName); + if (attrValue == null) { + log.debug("{} - skip execution: attribute {} has null value", filterName, isTestSpAttrName); + return true; + } else if (attrValue.valueAsBoolean()) { + log.debug("{} - redirecting user to test SP warning page", filterName); + this.redirect(request, response); + return false; + } + log.debug("{} - service is not testing, let user access it", filterName); + return true; + } + + private boolean testSpWarningApproved(HttpServletRequest req) { + if (req.getSession() == null) { + return false; + } + boolean approved = false; + if (req.getSession().getAttribute(IS_TEST_SP_APPROVED_SESS) != null) { + approved = (Boolean) req.getSession().getAttribute(IS_TEST_SP_APPROVED_SESS); + req.getSession().removeAttribute(IS_TEST_SP_APPROVED_SESS); + } + return approved; + } + + private void redirect(HttpServletRequest req, HttpServletResponse res) { + String targetURL = FiltersUtils.buildRequestURL(req); + + Map<String, String> params = new HashMap<>(); + params.put(PARAM_TARGET, targetURL); + String redirectUrl = ControllerUtils.createRedirectUrl(req, PerunFilterConstants.AUTHORIZE_REQ_PATTERN, + IsTestSpController.MAPPING, params); + log.debug("{} - redirecting user to testSP warning page: {}", filterName, redirectUrl); + res.reset(); + res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + res.setHeader(HttpHeaders.LOCATION, redirectUrl); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/ProxyStatisticsFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/ProxyStatisticsFilter.java new file mode 100644 index 000000000..984e1d18b --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/ProxyStatisticsFilter.java @@ -0,0 +1,204 @@ +package cz.muni.ics.oidc.server.filters.impl; + +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.SAML_EPUID; + +import cz.muni.ics.oidc.BeanUtil; +import cz.muni.ics.oidc.server.filters.FilterParams; +import cz.muni.ics.oidc.server.filters.FiltersUtils; +import cz.muni.ics.oidc.server.filters.PerunRequestFilter; +import cz.muni.ics.oidc.server.filters.PerunRequestFilterParams; +import java.sql.Connection; +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.LocalDate; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.sql.DataSource; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.saml.SAMLCredential; +import org.springframework.util.StringUtils; + + +/** + * Filter for collecting data about login. + * + * Configuration (replace [name] part with the name defined for the filter): + * <ul> + * <li><b>filter.[name].idpNameAttributeName</b> - Mapping to Request attribute containing name of used + * Identity Provider</li> + * <li><b>filter.[name].idpEntityIdAttributeName</b> - Mapping to Request attribute containing entity_id of used + * Identity Provider</li> + * <li><b>filter.[name].statisticsTableName</b> - Name of the table where to store data + * (depends on DataSource bean mitreIdStats)</li> + * <li><b>filter.[name].identityProvidersMapTableName</b> - Name of the table with mapping of entity_id (IDP) + * to idp name (depends on DataSource bean mitreIdStats) + * <li><b>filter.[name].serviceProvidersMapTableName</b> - Name of the table with mapping of client_id (SP) + * to client name (depends on DataSource bean mitreIdStats)</li> + * </ul> + * + * @author Dominik Baránek <baranek@ics.muni.cz> + */ +@SuppressWarnings("SqlResolve") +public class ProxyStatisticsFilter extends PerunRequestFilter { + + private static final Logger log = LoggerFactory.getLogger(ProxyStatisticsFilter.class); + + /* CONFIGURATION OPTIONS */ + private static final String IDP_NAME_ATTRIBUTE_NAME = "idpNameAttributeName"; + private static final String IDP_ENTITY_ID_ATTRIBUTE_NAME = "idpEntityIdAttributeName"; + private static final String STATISTICS_TABLE_NAME = "statisticsTableName"; + private static final String IDENTITY_PROVIDERS_MAP_TABLE_NAME = "identityProvidersMapTableName"; + private static final String SERVICE_PROVIDERS_MAP_TABLE_NAME = "serviceProvidersMapTableName"; + + private final String idpNameAttributeName; + private final String idpEntityIdAttributeName; + private final String statisticsTableName; + private final String identityProvidersMapTableName; + private final String serviceProvidersMapTableName; + /* END OF CONFIGURATION OPTIONS */ + + private final DataSource mitreIdStats; + private final String filterName; + + public ProxyStatisticsFilter(PerunRequestFilterParams params) { + super(params); + BeanUtil beanUtil = params.getBeanUtil(); + this.mitreIdStats = beanUtil.getBean("mitreIdStats", DataSource.class); + + this.idpNameAttributeName = params.getProperty(IDP_NAME_ATTRIBUTE_NAME); + this.idpEntityIdAttributeName = params.getProperty(IDP_ENTITY_ID_ATTRIBUTE_NAME); + this.statisticsTableName = params.getProperty(STATISTICS_TABLE_NAME); + this.identityProvidersMapTableName = params.getProperty(IDENTITY_PROVIDERS_MAP_TABLE_NAME); + this.serviceProvidersMapTableName = params.getProperty(SERVICE_PROVIDERS_MAP_TABLE_NAME); + this.filterName = params.getFilterName(); + } + + @Override + protected boolean process(ServletRequest req, ServletResponse res, FilterParams params) { + HttpServletRequest request = (HttpServletRequest) req; + + ClientDetailsEntity client = params.getClient(); + if (client == null) { + log.debug("{} - skip execution: no client provided", filterName); + return true; + } + + String clientIdentifier = client.getClientId(); + String clientName = client.getClientName(); + SAMLCredential samlCredential = FiltersUtils.getSamlCredential(request); + + String idpEntityId = samlCredential.getAttributeAsString(idpEntityIdAttributeName); + idpEntityId = this.changeParamEncoding(idpEntityId); + String idpName = samlCredential.getAttributeAsString(idpNameAttributeName); + idpName = this.changeParamEncoding(idpName); + if (!StringUtils.hasText(idpEntityId) || !StringUtils.hasText(idpName)) { + log.debug("{} - skip execution: no source IDP provided", filterName); + return true; + } + + String userId = samlCredential.getAttributeAsString(SAML_EPUID); + if (!StringUtils.hasText(userId)) { + log.debug("{} - skip execution: no user ID available", filterName); + return true; + } + + this.insertLogin(idpEntityId, idpName, clientIdentifier, clientName, userId); + this.logUserLogin(idpEntityId, clientIdentifier, clientName, userId); + + return true; + } + + private void insertLogin(String idpEntityId, String idpName, String spIdentifier, String spName, String userId) { + LocalDate date = LocalDate.now(); + String insertLoginQuery = "INSERT INTO " + statisticsTableName + "(day, idpId, spId, user, logins)" + + " VALUES(?, ?, ?, ?, '1') ON DUPLICATE KEY UPDATE logins = logins + 1"; + + try (Connection c = mitreIdStats.getConnection()) { + insertIdpMap(c, idpEntityId, idpName); + insertSpMap(c, spIdentifier, spName); + int idpId = extractIdpId(c, idpEntityId); + int spId = extractSpId(c, spIdentifier); + + try (PreparedStatement preparedStatement = c.prepareStatement(insertLoginQuery)) { + preparedStatement.setDate(1, Date.valueOf(date)); + preparedStatement.setInt(2, idpId); + preparedStatement.setInt(3, spId); + preparedStatement.setString(4, userId); + preparedStatement.execute(); + log.trace("{} - login entry stored ({}, {}, {}, {}, {})", filterName, idpEntityId, idpName, + spIdentifier, spName, userId); + } + } catch (SQLException ex) { + log.warn("{} - caught SQLException", filterName); + log.debug("{} - details:", filterName, ex); + } + } + + private int extractSpId(Connection c, String spIdentifier) throws SQLException { + String getSpIdQuery = "SELECT * FROM " + serviceProvidersMapTableName + " WHERE identifier= ?"; + + try (PreparedStatement preparedStatement = c.prepareStatement(getSpIdQuery)) { + preparedStatement.setString(1, spIdentifier); + ResultSet rs = preparedStatement.executeQuery(); + rs.first(); + return rs.getInt("spId"); + } + } + + private int extractIdpId(Connection c, String idpEntityId) throws SQLException { + String getIdPIdQuery = "SELECT * FROM " + identityProvidersMapTableName + " WHERE identifier = ?"; + + try (PreparedStatement preparedStatement = c.prepareStatement(getIdPIdQuery)) { + preparedStatement.setString(1, idpEntityId); + ResultSet rs = preparedStatement.executeQuery(); + rs.first(); + return rs.getInt("idpId"); + } + } + + private void insertSpMap(Connection c, String spIdentifier, String spName) throws SQLException { + String insertSpMapQuery = "INSERT INTO " + serviceProvidersMapTableName + "(identifier, name)" + + " VALUES (?, ?) ON DUPLICATE KEY UPDATE name = ?"; + + try (PreparedStatement preparedStatement = c.prepareStatement(insertSpMapQuery)) { + preparedStatement.setString(1, spIdentifier); + preparedStatement.setString(2, spName); + preparedStatement.setString(3, spName); + preparedStatement.execute(); + log.trace("{} - SP map entry inserted", filterName); + } + } + + private void insertIdpMap(Connection c, String idpEntityId, String idpName) throws SQLException { + String insertIdpMapQuery = "INSERT INTO " + identityProvidersMapTableName + "(identifier, name)" + + " VALUES (?, ?) ON DUPLICATE KEY UPDATE name = ?"; + + try (PreparedStatement preparedStatement = c.prepareStatement(insertIdpMapQuery)) { + preparedStatement.setString(1, idpEntityId); + preparedStatement.setString(2, idpName); + preparedStatement.setString(3, idpName); + preparedStatement.execute(); + log.trace("{} - IdP map entry inserted", filterName); + } + } + + private String changeParamEncoding(String original) { + if (original != null && !original.isEmpty()) { + byte[] sourceBytes = original.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1); + return new String(sourceBytes, java.nio.charset.StandardCharsets.UTF_8); + } + + return null; + } + + private void logUserLogin(String idpEntityId, String spIdentifier, String spName, String userId) { + log.info("User identity: {}, service: {}, serviceName: {}, via IdP: {}", userId, spIdentifier, + spName, idpEntityId); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/ValidUserFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/ValidUserFilter.java new file mode 100644 index 000000000..4ed4e5240 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/ValidUserFilter.java @@ -0,0 +1,181 @@ +package cz.muni.ics.oidc.server.filters.impl; + +import cz.muni.ics.oidc.BeanUtil; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.models.PerunUser; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig; +import cz.muni.ics.oidc.server.filters.FilterParams; +import cz.muni.ics.oidc.server.filters.FiltersUtils; +import cz.muni.ics.oidc.server.filters.PerunRequestFilter; +import cz.muni.ics.oidc.server.filters.PerunRequestFilterParams; +import cz.muni.ics.oidc.web.controllers.PerunUnapprovedController; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + + +/** + * Filter that decides if the user is valid or not. It checks for membership in specified groups and VOs. In addition, + * if service identifier is present and can be obtained, it also checks membership in specified groups and VOs based on + * the environment the service is in. + * + * Configuration (replace [name] part with the name defined for the filter): + * <ul> + * <li><b>filter.[name].allEnvGroups</b> - Comma separated list of GROUP IDs the user must be always member of</li> + * <li><b>filter.[name].allEnvGroups</b> - Comma separated list of VO IDs the user must be always member of</li> + * <li><b>filter.[name].testEnvGroups</b> - Comma separated list of GROUP IDs the user must be member of if service + * * is in the test environment</li> + * <li><b>filter.[name].testEnvVos</b> - Comma separated list of VO IDs the user must be member of if service + * * is in the test environment</li> + * <li><b>filter.[name].prodEnvGroups</b> - Comma separated list of GROUP IDs the user must be member of if service + * * is in the production environment</li> + * <li><b>filter.[name].prodEnvVos</b> - Comma separated list of VO IDs the user must be member of if service + * is in the production environment</li> + * </ul> + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@SuppressWarnings("SqlResolve") +public class ValidUserFilter extends PerunRequestFilter { + + private static final Logger log = LoggerFactory.getLogger(ValidUserFilter.class); + + /* CONFIGURATION OPTIONS */ + private static final String ALL_ENV_GROUPS = "allEnvGroups"; + private static final String ALL_ENV_VOS = "allEnvVos"; + private static final String TEST_ENV_GROUPS = "testEnvGroups"; + private static final String TEST_ENV_VOS = "testEnvVos"; + private static final String PROD_ENV_GROUPS = "prodEnvGroups"; + private static final String PROD_ENV_VOS = "prodEnvVos"; + + private final Set<Long> allEnvGroups; + private final Set<Long> allEnvVos; + private final Set<Long> testEnvGroups; + private final Set<Long> testEnvVos; + private final Set<Long> prodEnvGroups; + private final Set<Long> prodEnvVos; + /* END OF CONFIGURATION OPTIONS */ + + private final PerunAdapter perunAdapter; + private final FacilityAttrsConfig facilityAttrsConfig; + private final String filterName; + + public ValidUserFilter(PerunRequestFilterParams params) { + super(params); + BeanUtil beanUtil = params.getBeanUtil(); + this.perunAdapter = beanUtil.getBean(PerunAdapter.class); + this.facilityAttrsConfig = beanUtil.getBean(FacilityAttrsConfig.class); + + this.allEnvGroups = this.getIdsFromParam(params, ALL_ENV_GROUPS); + this.allEnvVos = this.getIdsFromParam(params, ALL_ENV_VOS); + this.testEnvGroups = this.getIdsFromParam(params, TEST_ENV_GROUPS); + this.testEnvVos = this.getIdsFromParam(params, TEST_ENV_VOS); + this.prodEnvGroups = this.getIdsFromParam(params, PROD_ENV_GROUPS); + this.prodEnvVos = this.getIdsFromParam(params, PROD_ENV_VOS); + this.filterName = params.getFilterName(); + } + + @Override + protected boolean process(ServletRequest req, ServletResponse res, FilterParams params) { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + + Set<Long> additionalVos = new HashSet<>(); + Set<Long> additionalGroups = new HashSet<>(); + + PerunUser user = params.getUser(); + + if (user == null || user.getId() == null) { + log.debug("{} - skip filter execution: no user provided", filterName); + return true; + } + + Facility facility = params.getFacility(); + if (facility == null || facility.getId() == null) { + log.debug("{} - skip filter execution: no facility provided", filterName); + return true; + } + + if (!checkMemberValidInGroupsAndVos(user, facility, request, response, params, allEnvVos, allEnvGroups, + PerunUnapprovedController.UNAPPROVED_NOT_IN_MANDATORY_VOS_GROUPS)) { + return false; + } + + PerunAttributeValue isTestSp = perunAdapter.getFacilityAttributeValue(facility.getId(), facilityAttrsConfig.getTestSpAttr()); + boolean isTestSpBool = false; + if (isTestSp != null) { + isTestSpBool = isTestSp.valueAsBoolean(); + } + log.debug("{} - service {} in test env", filterName, (isTestSpBool ? "is" : "is not")); + if (isTestSpBool) { + additionalVos.addAll(testEnvVos); + additionalGroups.addAll(testEnvGroups); + + if (!checkMemberValidInGroupsAndVos(user, facility, request, response, params, additionalVos, + additionalGroups, PerunUnapprovedController.UNAPPROVED_NOT_IN_TEST_VOS_GROUPS)) { + return false; + } + } else { + additionalVos.addAll(prodEnvVos); + additionalGroups.addAll(prodEnvGroups); + + if (!checkMemberValidInGroupsAndVos(user, facility, request, response, params, additionalVos, + additionalGroups, PerunUnapprovedController.UNAPPROVED_NOT_IN_PROD_VOS_GROUPS)) { + return false; + } + } + + log.info("{} - user satisfies the membership criteria", filterName); + return true; + } + + private Set<Long> getIdsFromParam(PerunRequestFilterParams params, String propKey) { + Set<Long> result = new HashSet<>(); + + String prop = params.getProperty(propKey); + if (StringUtils.hasText(prop)) { + String[] parts = prop.split(","); + for (String idStr: parts) { + result.add(Long.parseLong(idStr)); + } + } + + return result; + } + + private boolean checkMemberValidInGroupsAndVos( + PerunUser user, + Facility facility, + HttpServletRequest request, + HttpServletResponse response, + FilterParams params, + Set<Long> vos, + Set<Long> groups, + String redirectUrl + ) { + if (!perunAdapter.isValidMemberInGroupsAndVos(user.getId(), vos, groups)) { + log.info("{} - user is not member in required set of vos and groups", filterName); + log.debug("{} - user: '{}', vos: '{}', groups: '{}'", + filterName, user.getId(), vos, groups); + + Map<String, PerunAttributeValue> facilityAttributes = perunAdapter.getFacilityAttributeValues( + facility, facilityAttrsConfig.getMembershipAttrNames()); + + FiltersUtils.redirectUserCannotAccess(request, response, facility, user, params.getClientIdentifier(), + facilityAttrsConfig, facilityAttributes, perunAdapter, redirectUrl); + + return false; + } + return true; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/mdc/RemoteAddressMDCFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/mdc/RemoteAddressMDCFilter.java new file mode 100644 index 000000000..541b39c0d --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/mdc/RemoteAddressMDCFilter.java @@ -0,0 +1,43 @@ +package cz.muni.ics.oidc.server.filters.impl.mdc; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import org.slf4j.MDC; + +public class RemoteAddressMDCFilter { + + private static final String[] IP_HEADER_CANDIDATES = { + "X-Forwarded-For", + "Proxy-Client-IP", + "WL-Proxy-Client-IP", + "HTTP_X_FORWARDED_FOR", + "HTTP_X_FORWARDED", + "HTTP_X_CLUSTER_CLIENT_IP", + "HTTP_CLIENT_IP", + "HTTP_FORWARDED_FOR", + "HTTP_FORWARDED", + "HTTP_VIA", + "REMOTE_ADDR" + }; + + private static final String REMOTE_ADDR = "remoteAddr"; + + public void doFilter(ServletRequest servletRequest) { + MDC.put(REMOTE_ADDR, getRemoteAddr((HttpServletRequest) servletRequest)); + } + + private String getRemoteAddr(HttpServletRequest request) { + if (request.getRemoteAddr() != null) { + return request.getRemoteAddr(); + } + + for (String header: IP_HEADER_CANDIDATES) { + String ipList = request.getHeader(header); + if (ipList != null && ipList.length() != 0 && !"unknown".equalsIgnoreCase(ipList)) { + return ipList.split(",")[0]; + } + } + return "-"; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/mdc/SessionIdMDCFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/mdc/SessionIdMDCFilter.java new file mode 100644 index 000000000..f4ba622ed --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/mdc/SessionIdMDCFilter.java @@ -0,0 +1,23 @@ +package cz.muni.ics.oidc.server.filters.impl.mdc; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import org.slf4j.MDC; + +public class SessionIdMDCFilter { + + private static final int SIZE = 12; + private static final String SESSION_ID = "sessionID"; + + public void doFilter(ServletRequest servletRequest) { + HttpServletRequest req = (HttpServletRequest) servletRequest; + if (req.getSession() != null) { + String id = req.getSession().getId(); + if (id != null && id.length() > SIZE) { + id = id.substring(0, SIZE); + } + MDC.put(SESSION_ID, id); + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/PerunUserInfo.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/PerunUserInfo.java new file mode 100644 index 000000000..2e47845c0 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/PerunUserInfo.java @@ -0,0 +1,68 @@ +package cz.muni.ics.oidc.server.userInfo; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import java.util.LinkedHashMap; +import java.util.Map; +import cz.muni.ics.openid.connect.model.DefaultUserInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implements UserInfo by inheriting from DefaultUserInfo and adding more claims. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class PerunUserInfo extends DefaultUserInfo { + + private final static Logger log = LoggerFactory.getLogger(PerunUserInfo.class); + + private final Map<String, JsonNode> customClaims = new LinkedHashMap<>(); + private JsonObject obj; + + public Map<String, JsonNode> getCustomClaims() { + return customClaims; + } + + @Override + public JsonObject toJson() { + if (obj == null) { + //delegate standard claims to DefaultUserInfo + obj = super.toJson(); + //add custom claims + for (Map.Entry<String, JsonNode> entry : customClaims.entrySet()) { + String key = entry.getKey(); + JsonNode value = entry.getValue(); + if (value == null || value.isNull()) { + obj.addProperty(key, (String) null); + log.debug("adding null claim {}=null", key); + } else if (value.isTextual() || value.isBoolean()) { + obj.addProperty(key, value.asText()); + log.debug("adding string claim {}={}", key, value.asText()); + } else if (value.isNumber()) { + obj.addProperty(key, value.asLong()); + log.debug("adding long claim {}={}", key, value.asText()); + } else if (value.isContainerNode()) { + try { + //convert from Jackson to GSon + String rawJson = new ObjectMapper().writeValueAsString(value); + obj.add(key, new JsonParser().parse(rawJson)); + log.debug("adding JSON claim {}={}", key, rawJson); + } catch (JsonProcessingException | JsonSyntaxException e) { + log.error("cannot convert Jackson/Gson value " + value, e); + } + } else { + log.warn("claim {} is of unknown type {}, skipping", key, value.getNodeType().toString()); + } + } + } else { + log.debug("already rendered to JSON"); + } + return obj; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/PerunUserInfoService.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/PerunUserInfoService.java new file mode 100644 index 000000000..3e8f9031c --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/PerunUserInfoService.java @@ -0,0 +1,670 @@ +package cz.muni.ics.oidc.server.userInfo; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.TextNode; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.util.concurrent.UncheckedExecutionException; +import cz.muni.ics.oidc.exceptions.ConfigurationException; +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.models.PerunAttributeValueAwareModel; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.claims.ClaimContextCommonParameters; +import cz.muni.ics.oidc.server.claims.ClaimModifier; +import cz.muni.ics.oidc.server.claims.ClaimModifierInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSource; +import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext; +import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext; +import cz.muni.ics.oidc.server.claims.PerunCustomClaimDefinition; +import cz.muni.ics.oidc.server.claims.modifiers.NoOperationModifier; +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import javax.annotation.PostConstruct; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.model.Address; +import cz.muni.ics.openid.connect.model.DefaultAddress; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.service.UserInfoService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; + +/** + * Service called from UserInfoEndpoint and other places to get UserInfo. + * + * @author Martin Kuba <makub@ics.muni.cz> + */ +public class PerunUserInfoService implements UserInfoService { + + private static final Logger log = LoggerFactory.getLogger(PerunUserInfoService.class); + + private static final String CUSTOM_CLAIM = "custom.claim."; + private static final String SOURCE = ".source"; + private static final String CLASS = ".class"; + private static final String NAMES = ".names"; + private static final String MODIFIER = ".modifier"; + + @Autowired + private ClientDetailsEntityService clientService; + + @Autowired + private JWTSigningAndValidationService jwtService; + + @Autowired + private PerunOidcConfig perunOidcConfig; + + private List<String> forceRegenerateUserinfoCustomClaims = new ArrayList<>(); + private List<String> forceRegenerateUserinfoStandardClaims = new ArrayList<>(); + + private final LoadingCache<UserClientPair, UserInfo> cache; + + private PerunAdapter perunAdapter; + private Properties properties; + + private String subAttribute; + private List<ClaimModifier> subModifiers; + private String preferredUsernameAttribute; + private String givenNameAttribute; + private String familyNameAttribute; + private String middleNameAttribute; + private String fullNameAttribute; + private String emailAttribute; + private String addressAttribute; + private String phoneAttribute; + private String zoneinfoAttribute; + private String localeAttribute; + private Set<String> customClaimNames; + private List<PerunCustomClaimDefinition> customClaims = new ArrayList<>(); + private UserInfoModifierContext userInfoModifierContext; + + private final Set<String> userAttrNames = new HashSet<>(); + + public void setProperties(Properties properties) { + this.properties = properties; + } + + public void setPerunAdapter(PerunAdapter perunAdapter) { + this.perunAdapter = perunAdapter; + } + + public void setSubAttribute(String subAttribute) { + if (this.subAttribute != null) { + userAttrNames.remove(this.subAttribute); + } + userAttrNames.add(subAttribute); + this.subAttribute = subAttribute; + } + + public void setPreferredUsernameAttribute(String preferredUsernameAttribute) { + if (this.preferredUsernameAttribute != null) { + userAttrNames.remove(this.preferredUsernameAttribute); + } + userAttrNames.add(preferredUsernameAttribute); + this.preferredUsernameAttribute = preferredUsernameAttribute; + } + + public void setGivenNameAttribute(String givenNameAttribute) { + if (this.givenNameAttribute != null) { + userAttrNames.remove(this.givenNameAttribute); + } + userAttrNames.add(givenNameAttribute); + this.givenNameAttribute = givenNameAttribute; + } + + public void setFamilyNameAttribute(String familyNameAttribute) { + if (this.familyNameAttribute != null) { + userAttrNames.remove(this.familyNameAttribute); + } + userAttrNames.add(familyNameAttribute); + this.familyNameAttribute = familyNameAttribute; + } + + public void setMiddleNameAttribute(String middleNameAttribute) { + if (this.middleNameAttribute != null) { + userAttrNames.remove(this.middleNameAttribute); + } + userAttrNames.add(middleNameAttribute); + this.middleNameAttribute = middleNameAttribute; + } + + public void setFullNameAttribute(String fullNameAttribute) { + if (this.fullNameAttribute != null) { + userAttrNames.remove(this.fullNameAttribute); + } + userAttrNames.add(fullNameAttribute); + this.fullNameAttribute = fullNameAttribute; + } + + public void setEmailAttribute(String emailAttribute) { + if (this.emailAttribute != null) { + userAttrNames.remove(this.emailAttribute); + } + userAttrNames.add(emailAttribute); + this.emailAttribute = emailAttribute; + } + + public void setAddressAttribute(String addressAttribute) { + if (this.addressAttribute != null) { + userAttrNames.remove(this.addressAttribute); + } + userAttrNames.add(addressAttribute); + this.addressAttribute = addressAttribute; + } + + public void setPhoneAttribute(String phoneAttribute) { + if (this.phoneAttribute != null) { + userAttrNames.remove(this.phoneAttribute); + } + userAttrNames.add(phoneAttribute); + this.phoneAttribute = phoneAttribute; + } + + public void setZoneinfoAttribute(String zoneinfoAttribute) { + if (this.zoneinfoAttribute != null) { + userAttrNames.remove(this.zoneinfoAttribute); + } + userAttrNames.add(zoneinfoAttribute); + this.zoneinfoAttribute = zoneinfoAttribute; + } + + public void setLocaleAttribute(String localeAttribute) { + if (this.localeAttribute != null) { + userAttrNames.remove(this.localeAttribute); + } + userAttrNames.add(localeAttribute); + this.localeAttribute = localeAttribute; + } + + public void setCustomClaimNames(Set<String> customClaimNames) { + this.customClaimNames = customClaimNames; + } + + public void setForceRegenerateUserinfoCustomClaims(String[] claims) { + this.forceRegenerateUserinfoCustomClaims = Arrays.asList(claims); + } + + public void setForceRegenerateUserinfoStandardClaims(String[] claims) { + this.forceRegenerateUserinfoStandardClaims = Arrays.asList(claims); + } + + public List<PerunCustomClaimDefinition> getCustomClaims() { + return customClaims; + } + + @PostConstruct + public void postInit() throws ConfigurationException { + log.debug("trying to load modifier for attribute.openid.sub"); + subModifiers = loadClaimValueModifiers("sub", "attribute.openid.sub" + MODIFIER); + //custom claims + this.customClaims = new ArrayList<>(customClaimNames.size()); + for (String claimName : customClaimNames) { + String propertyBase = CUSTOM_CLAIM + claimName; + //get scope + String scopeProperty = propertyBase + ".scope"; + String scope = properties.getProperty(scopeProperty); + if (scope == null) { + log.error("property {} not found, skipping custom claim {}", scopeProperty, claimName); + continue; + } + //get ClaimSource + ClaimSource claimSource = loadClaimSource(claimName, propertyBase + SOURCE); + userAttrNames.addAll(claimSource.getAttrIdentifiers()); + //optional claim value modifier + List<ClaimModifier> claimModifiers = loadClaimValueModifiers(claimName, propertyBase + MODIFIER); + //add claim definition + customClaims.add(new PerunCustomClaimDefinition(scope, claimName, claimSource, claimModifiers)); + + } + + this.userInfoModifierContext = new UserInfoModifierContext(properties, perunAdapter); + } + + @Override + public UserInfo getByUsernameAndClientId(String username, String clientId) { + ClientDetailsEntity client = clientService.loadClientByClientId(clientId); + if (client == null) { + log.warn("did not found client with id {}", clientId); + return null; + } + + PerunUserInfo userInfo; + try { + UserClientPair cacheKey = new UserClientPair(username, clientId, client); + userInfo = (PerunUserInfo) cache.get(cacheKey); + if (!checkStandardClaims(userInfo) || !checkCustomClaims(userInfo)) { + log.info("Some required claim is null, regenerate userInfo"); + cache.invalidate(cacheKey); + userInfo = (PerunUserInfo) cache.get(cacheKey); + } + log.debug("loaded UserInfo from cache for '{}'/'{}'", userInfo.getName(), client.getClientName()); + userInfo = userInfoModifierContext.modify(userInfo, clientId); + } catch (ExecutionException e) { + log.error("cannot get user from cache", e); + return null; + } + + return userInfo; + } + + @Override + public UserInfo getByUsername(String username) { + PerunUserInfo userInfo; + try { + UserClientPair cacheKey = new UserClientPair(username); + userInfo = (PerunUserInfo) cache.get(cacheKey); + if (!checkStandardClaims(userInfo) || !checkCustomClaims(userInfo)) { + log.info("Some required claim is null, regenerate userInfo"); + cache.invalidate(cacheKey); + userInfo = (PerunUserInfo) cache.get(cacheKey); + } + log.debug("loaded UserInfo from cache for '{}'", userInfo.getName()); + userInfo = userInfoModifierContext.modify(userInfo, null); + } catch (UncheckedExecutionException | ExecutionException e) { + log.error("cannot get user from cache", e); + return null; + } + + return userInfo; + } + + @Override + public UserInfo getByEmailAddress(String email) { + throw new RuntimeException("PerunUserInfoService.getByEmailAddress() not implemented"); + } + + public PerunUserInfoService() { + this.cache = CacheBuilder.newBuilder() + .maximumSize(100) + .expireAfterAccess(60, TimeUnit.SECONDS) + .build(cacheLoader); + } + + private List<ClaimModifier> loadClaimValueModifiers(String claimName, String propertyPrefix) + throws ConfigurationException + { + String names = properties.getProperty(propertyPrefix + NAMES, ""); + String[] nameArr = names.split(","); + List<ClaimModifier> modifiers = new ArrayList<>(); + if (nameArr.length > 0) { + for (String name : nameArr) { + modifiers.add(loadClaimValueModifier(claimName, propertyPrefix + '.' + name, name)); + } + } + return modifiers; + } + + private ClaimModifier loadClaimValueModifier(String claimName, String propertyPrefix, String modifierName) + throws ConfigurationException + { + String modifierClass = properties.getProperty(propertyPrefix + CLASS, NoOperationModifier.class.getName()); + if (!StringUtils.hasText(modifierClass)) { + log.debug("{}:{} - no class has ben configured for claim value modifier, use noop modifier", + claimName, modifierName); + modifierClass = NoOperationModifier.class.getName(); + } + log.trace("{}:{} - loading ClaimModifier class '{}'", claimName, modifierName, modifierClass); + + try { + Class<?> rawClazz = Class.forName(modifierClass); + if (!ClaimModifier.class.isAssignableFrom(rawClazz)) { + log.error("{}:{} - failed to initialized claim modifier: class '{}' does not extend ClaimModifier", + claimName, modifierName, modifierClass); + throw new ConfigurationException("No instantiable class modifier configured for claim " + claimName); + } + @SuppressWarnings("unchecked") Class<ClaimModifier> clazz = (Class<ClaimModifier>) rawClazz; + Constructor<ClaimModifier> constructor = clazz.getConstructor(ClaimModifierInitContext.class); + ClaimModifierInitContext ctx = new ClaimModifierInitContext( + propertyPrefix, properties, claimName, modifierName); + return constructor.newInstance(ctx); + } catch (ClassNotFoundException e) { + log.error("{}:{} - failed to initialize claim modifier: class '{}' was not found", + claimName, modifierName, modifierClass); + log.trace("{}:{} - details:", claimName, modifierName, e); + throw new ConfigurationException("Error has occurred when instantiating claim modifier '" + + modifierName + "' of claim '" + claimName + '\''); + } catch (NoSuchMethodException e) { + log.error("{}:{} - failed to initialize claim modifier: class '{}' does not have proper constructor", + claimName, modifierName, modifierClass); + log.trace("{}:{} - details:", claimName, e); + throw new ConfigurationException("Error has occurred when instantiating claim modifier '" + + modifierName + "' of claim '" + claimName + '\''); + } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + log.error("{}:{} - failed to initialize claim modifier: class '{}' cannot be instantiated", + claimName, modifierName, modifierClass); + log.trace("{}:{} - details:", claimName, e); + throw new ConfigurationException("Error has occurred when instantiating claim modifier '" + + modifierName + "' of claim '" + claimName + '\''); + } + } + + private ClaimSource loadClaimSource(String claimName, String propertyPrefix) throws ConfigurationException { + String sourceClass = properties.getProperty(propertyPrefix + CLASS); + if (!StringUtils.hasText(sourceClass)) { + log.error("{} - failed to initialized claim source: no class has ben configured", claimName); + throw new ConfigurationException("No class configured for claim source"); + } + + log.trace("{} - loading ClaimSource class '{}'", claimName, sourceClass); + + try { + Class<?> rawClazz = Class.forName(sourceClass); + if (!ClaimSource.class.isAssignableFrom(rawClazz)) { + log.error("{} - failed to initialized claim source: class '{}' does not extend ClaimSource", + claimName, sourceClass); + throw new ConfigurationException("No instantiable class source configured for claim " + claimName); + } + @SuppressWarnings("unchecked") Class<ClaimSource> clazz = (Class<ClaimSource>) rawClazz; + Constructor<ClaimSource> constructor = clazz.getConstructor(ClaimSourceInitContext.class); + ClaimSourceInitContext ctx = new ClaimSourceInitContext(perunOidcConfig, jwtService, propertyPrefix, + properties, claimName); + return constructor.newInstance(ctx); + } catch (ClassNotFoundException e) { + log.error("{} - failed to initialize claim source: class '{}' was not found", claimName, sourceClass); + log.trace("{} - details:", claimName, e); + throw new ConfigurationException("Error has occurred when instantiating claim source for claim " + claimName); + } catch (NoSuchMethodException e) { + log.error("{} - failed to initialize claim source: class '{}' does not have proper constructor", + claimName, sourceClass); + log.trace("{} - details:", claimName, e); + throw new ConfigurationException("Error has occurred when instantiating claim source for claim " + claimName); + } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + log.error("{} - failed to initialize claim source: class '{}' cannot be instantiated", claimName, sourceClass); + log.trace("{} - details:", claimName, e); + throw new ConfigurationException("Error has occurred when instantiating claim source for claim " + claimName); + } + } + + private static class UserClientPair { + private final long userId; + private String clientId; + private ClientDetailsEntity client; + + UserClientPair(String userId) { + this.userId = Long.parseLong(userId); + } + + UserClientPair(String userId, String clientId, ClientDetailsEntity client) { + this.userId = Long.parseLong(userId); + this.clientId = clientId; + this.client = client; + } + + public long getUserId() { + return userId; + } + + public String getClientId() { + return clientId; + } + + public ClientDetailsEntity getClient() { + return client; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UserClientPair that = (UserClientPair) o; + return userId == that.userId && + Objects.equals(clientId, that.clientId); + } + + @Override + public int hashCode() { + return Objects.hash(userId, clientId); + } + + @Override + public String toString() { + return "(" + "userId=" + userId + "," + (client == null ? "null" : "client=" + clientId + " '" + client.getClientName()) + "')"; + } + } + + @SuppressWarnings("FieldCanBeLocal") + private final CacheLoader<UserClientPair, UserInfo> cacheLoader = new CacheLoader<UserClientPair, UserInfo>() { + @Override + public UserInfo load(UserClientPair pair) { + log.debug("load({}) ... populating cache for the key", pair); + PerunUserInfo ui = new PerunUserInfo(); + long perunUserId = pair.getUserId(); + + Map<String, PerunAttributeValue> userAttributeValues = perunAdapter.getUserAttributeValues(perunUserId, userAttrNames); + + if (shouldFillAttrs(userAttributeValues)) { + List<String> attrNames = userAttributeValues.entrySet() + .stream() + .filter(entry -> (null == entry.getValue() || entry.getValue().isNullValue())) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + Map<String, PerunAttributeValue> missingAttrs = perunAdapter.getAdapterFallback() + .getUserAttributeValues(perunUserId, attrNames); + for (Map.Entry<String, PerunAttributeValue> entry : missingAttrs.entrySet()) { + userAttributeValues.put(entry.getKey(), entry.getValue()); + } + } + + JsonNode subJson = userAttributeValues.get(subAttribute).valueAsJson(); + if (subJson == null || subJson.isNull() || !StringUtils.hasText(subJson.asText())) { + throw new RuntimeException("cannot get sub from attribute " + subAttribute + " for username " + perunUserId); + } + String sub = subJson.asText(); + if (subModifiers != null) { + subJson = modifyClaims(subModifiers, subJson); + sub = subJson.asText(); + if (sub == null || !StringUtils.hasText(sub)) { + throw new RuntimeException("Sub has no value after modification for username " + perunUserId); + } + } + + ui.setId(perunUserId); + ui.setSub(sub); // Subject - Identifier for the End-User at the Issuer. + + ui.setPreferredUsername(userAttributeValues.get(preferredUsernameAttribute).valueAsString()); // Shorthand name by which the End-User wishes to be referred to at the RP + ui.setGivenName(userAttributeValues.get(givenNameAttribute).valueAsString()); // Given name(s) or first name(s) of the End-User + ui.setFamilyName(userAttributeValues.get(familyNameAttribute).valueAsString()); // Surname(s) or last name(s) of the End-User + ui.setMiddleName(userAttributeValues.get(middleNameAttribute).valueAsString()); // Middle name(s) of the End-User + ui.setName(userAttributeValues.get(fullNameAttribute).valueAsString()); // End-User's full name + //ui.setNickname(); // Casual name of the End-User + //ui.setProfile(); // URL of the End-User's profile page. + //ui.setPicture(); // URL of the End-User's profile picture. + //ui.setWebsite(); // URL of the End-User's Web page or blog. + ui.setEmail(userAttributeValues.get(emailAttribute).valueAsString()); // End-User's preferred e-mail address. + //ui.setEmailVerified(true); // True if the End-User's e-mail address has been verified + //ui.setGender("male"); // End-User's gender. Values defined by this specification are female and male. + //ui.setBirthdate("1975-01-01");//End-User's birthday, represented as an ISO 8601:2004 [ISO8601‑2004] YYYY-MM-DD format. + ui.setZoneinfo(userAttributeValues.get(zoneinfoAttribute).valueAsString());//String from zoneinfo [zoneinfo] time zone database, For example, Europe/Paris + ui.setLocale(userAttributeValues.get(localeAttribute).valueAsString()); // For example, en-US or fr-CA. + ui.setPhoneNumber(userAttributeValues.get(phoneAttribute).valueAsString()); //[E.164] is RECOMMENDED as the format, for example, +1 (425) 555-121 + //ui.setPhoneNumberVerified(true); // True if the End-User's phone number has been verified + //ui.setUpdatedTime(Long.toString(System.currentTimeMillis()/1000L));// value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time + Address address = null; + if (StringUtils.hasText(userAttributeValues.get(addressAttribute).valueAsString())) { + address = new DefaultAddress(); + address.setFormatted(userAttributeValues.get(addressAttribute).valueAsString()); + //address.setStreetAddress("Šumavská 15"); + //address.setLocality("Brno"); + //address.setPostalCode("61200"); + //address.setCountry("Czech Republic"); + } + ui.setAddress(address); + //custom claims + ClaimContextCommonParameters contextCommonParameters = getClaimContextCommonParameters(perunUserId, + pair.getClientId(), perunAdapter); + ClaimSourceProduceContext pctx = new ClaimSourceProduceContext(perunUserId, sub, userAttributeValues, + perunAdapter, pair.getClient(), contextCommonParameters); + log.debug("processing custom claims"); + for (PerunCustomClaimDefinition pccd : customClaims) { + log.debug("producing value for custom claim {}", pccd.getClaim()); + JsonNode claimInJson = pccd.getClaimSource().produceValue(pctx); + log.debug("produced value {}={}", pccd.getClaim(), claimInJson); + if (claimInJson == null || claimInJson.isNull()) { + log.debug("claim {} is null", pccd.getClaim()); + continue; + } else if (claimInJson.isTextual() && !StringUtils.hasText(claimInJson.asText())) { + log.debug("claim {} is a string and it is empty or null", pccd.getClaim()); + continue; + } else if ((claimInJson.isArray() || claimInJson.isObject()) && claimInJson.size() == 0) { + log.debug("claim {} is an object or array and it is empty or null", pccd.getClaim()); + continue; + } + List<ClaimModifier> claimModifiers = pccd.getClaimModifiers(); + if (claimModifiers != null && !claimModifiers.isEmpty()) { + claimInJson = modifyClaims(claimModifiers, claimInJson); + } + ui.getCustomClaims().put(pccd.getClaim(), claimInJson); + } + log.debug("UserInfo created"); + return ui; + } + + private ClaimContextCommonParameters getClaimContextCommonParameters(long perunUserId, String clientId, + PerunAdapter perunAdapter) + { + Facility facility = perunAdapter.getFacilityByClientId(clientId); + return new ClaimContextCommonParameters(facility); + } + }; + + private JsonNode modifyClaims(List<ClaimModifier> claimModifiers, JsonNode value) { + for (ClaimModifier modifier: claimModifiers) { + value = modifyClaim(modifier, value); + } + return value; + } + + private JsonNode modifyClaim(ClaimModifier modifier, JsonNode orig) { + JsonNode claimInJson = orig.deepCopy(); + if (claimInJson.isTextual()) { + return TextNode.valueOf(modifier.modify(claimInJson.asText())); + } else if (claimInJson.isArray()) { + ArrayNode arrayNode = (ArrayNode) claimInJson; + for (int i = 0; i < arrayNode.size(); i++) { + JsonNode item = arrayNode.get(i); + if (item.isTextual()) { + String original = item.asText(); + String modified = modifier.modify(original); + arrayNode.set(i, TextNode.valueOf(modified)); + } + } + return arrayNode; + } else { + log.warn("Original value is neither string nor array of strings - cannot modify values"); + return orig; + } + } + + private boolean shouldFillAttrs(Map<String, PerunAttributeValue> userAttributeValues) { + if (perunOidcConfig.isFillMissingUserAttrs()) { + if (userAttributeValues.isEmpty()) { + return true; + } else if (userAttributeValues.containsValue(null)) { + return true; + } else { + return !userAttributeValues.values().stream() + .filter(PerunAttributeValueAwareModel::isNullValue) + .collect(Collectors.toSet()) + .isEmpty(); + } + } + return false; + } + + private boolean checkStandardClaims(PerunUserInfo userInfo) { + for (String claim: forceRegenerateUserinfoStandardClaims) { + switch (claim.toLowerCase()) { + case "sub": { + if (userInfo.getSub() == null) { + return false; + } + } break; + case "preferred_username": { + if (userInfo.getPreferredUsername() == null) { + return false; + } + } break; + case "given_name": { + if (userInfo.getGivenName() == null) { + return false; + } + } break; + case "family_name": { + if (userInfo.getFamilyName() == null) { + return false; + } + } break; + case "middle_name": { + if (userInfo.getMiddleName() == null) { + return false; + } + } break; + case "name": { + if (userInfo.getName() == null) { + return false; + } + } break; + case "email": { + if (userInfo.getEmail() == null) { + return false; + } + } break; + case "address_formatted": { + if (userInfo.getAddress() == null + || userInfo.getAddress().getFormatted() == null) + { + return false; + } + } break; + case "phone": { + if (userInfo.getPhoneNumber() == null) { + return false; + } + } break; + case "zoneinfo": { + if (userInfo.getZoneinfo() == null) { + return false; + } + } break; + case "locale": { + if (userInfo.getLocale() == null) { + return false; + } + } break; + } + } + + log.debug("All required standard claims are OK"); + return true; + } + + private boolean checkCustomClaims(PerunUserInfo userInfo) { + for (String claim: forceRegenerateUserinfoCustomClaims) { + if (userInfo.getCustomClaims().get(claim) == null || + userInfo.getCustomClaims().get(claim).isNull()) { + return false; + } + } + + log.debug("All required custom claims are OK"); + return true; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/UserInfoModifier.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/UserInfoModifier.java new file mode 100644 index 000000000..ffb683450 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/UserInfoModifier.java @@ -0,0 +1,32 @@ +package cz.muni.ics.oidc.server.userInfo; + +/** + * Interface for all code that needs to modify user info. + * + * Configuration of userInfo modifiers: + * <ul> + * <li><b>userInfo.modifiers</b> - comma separated list of names of the userInfo modifiers</li> + * </ul> + * + * Configuration of modifier (replace [name] part with the name defined for the modifier): + * <ul> + * <li><b>userInfo.modifier.[name].class</b> - class the modifier instantiates</li> + * </ul> + * + * @see cz.muni.ics.oidc.server.userInfo.modifiers package for specific modifiers and their configuration + * + * @author Dominik Baránek <baranek@ics.muni.cz> + */ +public interface UserInfoModifier { + + /** + * Performs modification of UserInfo object. Modification depends on implementation. + * ATTENTION: param clientId can be NULL. In that case, implementation should not fail, modification should be + * rather skipped. + * + * @param perunUserInfo UserInfo to be modified + * @param clientId Id of client. Can be null. + */ + void modify(PerunUserInfo perunUserInfo, String clientId); + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/UserInfoModifierContext.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/UserInfoModifierContext.java new file mode 100644 index 000000000..0db8fc579 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/UserInfoModifierContext.java @@ -0,0 +1,83 @@ +package cz.muni.ics.oidc.server.userInfo; + +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Context for UserInfoModifiers. + * + * @author Dominik Baránek <baranek@ics.muni.cz> + */ +public class UserInfoModifierContext { + + private static final Logger log = LoggerFactory.getLogger(PerunUserInfoService.class); + + private static final String MODIFIER_CLASS = ".class"; + + private final Properties properties; + private final PerunAdapter perunAdapter; + private final List<UserInfoModifier> modifiers; + + public UserInfoModifierContext(Properties properties, PerunAdapter perunAdapter) { + this.properties = properties; + this.perunAdapter = perunAdapter; + this.modifiers = new LinkedList<>(); + + String modifierNamesProperty = properties.getProperty("userInfo.modifiers"); + String[] modifierNames = modifierNamesProperty.split(","); + for (String m : modifierNames) { + UserInfoModifier modifier = loadModifier("userInfo.modifier." + m); + if (modifier != null) { + log.debug("Executing modifier {}", m); + modifiers.add(modifier); + } + } + + } + + public PerunUserInfo modify(PerunUserInfo perunUserInfo, String clientId) { + for (UserInfoModifier m : modifiers) { + m.modify(perunUserInfo, clientId); + } + + return perunUserInfo; + } + + private UserInfoModifier loadModifier(String propertyPrefix) { + + String modifierClass = properties.getProperty(propertyPrefix + MODIFIER_CLASS, null); + if (modifierClass == null) { + return null; + } + try { + Class<?> rawClazz = Class.forName(modifierClass); + if (!UserInfoModifier.class.isAssignableFrom(rawClazz)) { + log.error("modifier class {} does not extend UserInfoModifier", modifierClass); + return null; + } + @SuppressWarnings("unchecked") Class<UserInfoModifier> clazz = (Class<UserInfoModifier>) rawClazz; + Constructor<UserInfoModifier> constructor = clazz.getConstructor(UserInfoModifierInitContext.class); + UserInfoModifierInitContext ctx = new UserInfoModifierInitContext(propertyPrefix, properties, perunAdapter); + UserInfoModifier userInfoModifier = constructor.newInstance(ctx); + log.info("loaded a modifier '{}' for {}", userInfoModifier, propertyPrefix); + return userInfoModifier; + } catch (ClassNotFoundException e) { + log.error("modifier class {} not found", modifierClass); + return null; + } catch (NoSuchMethodException e) { + log.error("modifier class {} does not have proper constructor", modifierClass); + return null; + } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + log.error("cannot instantiate " + modifierClass, e); + log.error("modifier class {} cannot be instantiated", modifierClass); + return null; + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/UserInfoModifierInitContext.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/UserInfoModifierInitContext.java new file mode 100644 index 000000000..8ddf2e99c --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/userInfo/UserInfoModifierInitContext.java @@ -0,0 +1,36 @@ +package cz.muni.ics.oidc.server.userInfo; + + +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import java.util.Properties; + +/** + * Context for initializing UserInfoModifiers. + * + * @author Dominik Baránek <baranek@ics.muni.cz> + */ +public class UserInfoModifierInitContext { + + private final String propertyPrefix; + private final Properties properties; + private PerunAdapter perunAdapter; + + public UserInfoModifierInitContext(String propertyPrefix, Properties properties, PerunAdapter perunAdapter) { + this.propertyPrefix = propertyPrefix; + this.properties = properties; + this.perunAdapter = perunAdapter; + } + + public String getProperty(String suffix, String defaultValue) { + return properties.getProperty(propertyPrefix + "." + suffix, defaultValue); + } + + public PerunAdapter getPerunAdapter() { + return perunAdapter; + } + + public void setPerunAdapter(PerunAdapter perunAdapter) { + this.perunAdapter = perunAdapter; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/WebHtmlClasses.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/WebHtmlClasses.java new file mode 100644 index 000000000..90c02c159 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/WebHtmlClasses.java @@ -0,0 +1,65 @@ +package cz.muni.ics.oidc.web; + +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Static utility class for HTML pages. Contains properties that can be rendered as element classes in HTML. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class WebHtmlClasses { + + private static final Logger log = LoggerFactory.getLogger(WebHtmlClasses.class); + + private String classesFilePath; + private Properties webHtmlClassesProperties; + + public WebHtmlClasses(PerunOidcConfig perunOidcConfig) { + this.classesFilePath = perunOidcConfig.getWebClassesFilePath(); + initFile(); + } + + public String getClassesFilePath() { + return classesFilePath; + } + + public Properties getWebHtmlClassesProperties() { + return webHtmlClassesProperties; + } + + private void initFile() { + Properties webHtmlClassesProps = new Properties(); + String resourceFileName = "web_classes/web_html_classes.properties"; + try (InputStreamReader isr = new InputStreamReader(Objects.requireNonNull( + getClass().getClassLoader().getResourceAsStream(resourceFileName)),StandardCharsets.UTF_8)) { + webHtmlClassesProps.load(isr); + log.debug("Loaded web html classes file: {}", resourceFileName); + } catch (IOException e) { + log.warn("Exception caught when reading {}", resourceFileName, e); + } + + String customFileName = classesFilePath; + try (InputStreamReader isr = new InputStreamReader( + new FileInputStream(customFileName), StandardCharsets.UTF_8 + )) { + webHtmlClassesProps.load(isr); + log.debug("Loaded web html classes file: {}", customFileName); + } catch (FileNotFoundException e) { + log.warn("File: {} not found", customFileName); + e.printStackTrace(); + } catch (IOException e) { + log.warn("Exception caught when reading {}", customFileName, e); + } + + this.webHtmlClassesProperties = webHtmlClassesProps; + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/ApproveDeviceController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/ApproveDeviceController.java new file mode 100644 index 000000000..7d86b5973 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/ApproveDeviceController.java @@ -0,0 +1,219 @@ +package cz.muni.ics.oidc.web.controllers; + +import cz.muni.ics.oidc.server.PerunDeviceCodeAcrRepository; +import cz.muni.ics.oidc.server.PerunScopeClaimTranslationService; +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.server.filters.PerunFilterConstants; +import cz.muni.ics.oidc.server.userInfo.PerunUserInfo; +import cz.muni.ics.oidc.web.WebHtmlClasses; +import cz.muni.ics.oidc.web.langs.Localization; +import java.security.Principal; +import java.time.Instant; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.DeviceCode; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.oauth2.web.DeviceEndpoint; +import cz.muni.ics.openid.connect.models.DeviceCodeAcr; +import cz.muni.ics.openid.connect.service.UserInfoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.provider.AuthorizationRequest; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +@Controller +public class ApproveDeviceController { + + public static final String DEVICE = "device"; + public static final String APPROVE_DEVICE = "approveDevice"; + public static final String DEVICE_APPROVED = "deviceApproved"; + public static final String REQUEST_USER_CODE = "requestUserCode"; + public static final String USER_CODE = "user_code"; + public static final String DEVICE_CODE = "device_code"; + public static final String USER_OAUTH_APPROVAL = "user_oauth_approval"; + public static final String URL = "devicecode"; + public static final String VERIFICATION_URI = "verification_uri"; + public static final String VERIFICATION_URI_COMPLETE = "verification_uri_complete"; + public static final String ACR_VALUES = "acr_values"; + public static final String ENTITY = "entity"; + public static final String CLIENT_ID = "client_id"; + public static final String SCOPE = "scope"; + public static final String ACR = "acr"; + + private final SystemScopeService scopeService; + private final DeviceEndpoint deviceEndpoint; + private final PerunOidcConfig perunOidcConfig; + private final Localization localization; + private final WebHtmlClasses htmlClasses; + private final PerunScopeClaimTranslationService scopeClaimTranslationService; + private final UserInfoService userInfoService; + private final PerunDeviceCodeAcrRepository deviceCodeAcrRepository; + + @Autowired + public ApproveDeviceController(SystemScopeService scopeService, + DeviceEndpoint deviceEndpoint, + PerunOidcConfig perunOidcConfig, + Localization localization, + WebHtmlClasses htmlClasses, + PerunScopeClaimTranslationService scopeClaimTranslationService, + UserInfoService userInfoService, + PerunDeviceCodeAcrRepository perunDeviceCodeAcrRepository) + { + this.scopeService = scopeService; + this.deviceEndpoint = deviceEndpoint; + this.perunOidcConfig = perunOidcConfig; + this.localization = localization; + this.htmlClasses = htmlClasses; + this.scopeClaimTranslationService = scopeClaimTranslationService; + this.userInfoService = userInfoService; + this.deviceCodeAcrRepository = perunDeviceCodeAcrRepository; + } + + @RequestMapping( + value = {"/" + URL}, + method = RequestMethod.POST, + consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE}, + produces = {MediaType.APPLICATION_JSON_VALUE}, + params = {CLIENT_ID, ACR_VALUES} + ) + public String requestDeviceCodeMFA(@RequestParam(CLIENT_ID) String clientId, @RequestParam(name = SCOPE, required = false) String scope, + @RequestParam(name = ACR_VALUES) String acrValues, Map<String, String> parameters, ModelMap model) + { + String result = deviceEndpoint.requestDeviceCode(clientId, scope, parameters, model); + + Map<String, Object> response = (Map<String, Object>) model.get(ENTITY); + response.replace(VERIFICATION_URI, response.get(VERIFICATION_URI) + "?" + ACR_VALUES + "=" + acrValues); + response.replace(VERIFICATION_URI_COMPLETE, response.get(VERIFICATION_URI_COMPLETE) + "&" + ACR_VALUES + "=" + acrValues); + storeAcrBase((String) response.get(DEVICE_CODE), (String)response.get(USER_CODE)); + + return result; + } + + @PreAuthorize("hasRole('ROLE_USER')") + @GetMapping(value = "/" + DEVICE, + consumes = {"text/html", "application/xhtml+xml","application/xml;q=0.9","image/webp","*/*;q=0.8"}) + public String requestUserCode(@RequestParam(value = USER_CODE, required = false) String userCode, + @ModelAttribute("authorizationRequest") AuthorizationRequest authRequest, + Principal p, + HttpServletRequest req, + ModelMap model, + HttpSession session) + { + String result = deviceEndpoint.requestUserCode(userCode, model, session); + if (result.equals(REQUEST_USER_CODE) && !perunOidcConfig.getTheme().equalsIgnoreCase("default")) { + ControllerUtils.setPageOptions(model, req, localization, htmlClasses, perunOidcConfig); + model.put("page", REQUEST_USER_CODE); + String shibAuthnContextClass = ""; + if (StringUtils.hasText(req.getParameter(ACR_VALUES))) { + shibAuthnContextClass = (String) req.getAttribute(PerunFilterConstants.SHIB_AUTHN_CONTEXT_CLASS); + if (!StringUtils.hasText(shibAuthnContextClass)) { + shibAuthnContextClass = (String) req.getAttribute(PerunFilterConstants.SHIB_AUTHN_CONTEXT_METHOD); + } + if (!StringUtils.hasText(shibAuthnContextClass)) { + shibAuthnContextClass = ""; + } + } + model.put(ACR, shibAuthnContextClass); + return "themedRequestUserCode"; + } else if (result.equals(APPROVE_DEVICE) && !perunOidcConfig.getTheme().equalsIgnoreCase("default")) { + return themedApproveDevice(model, p, req); + } + return result; + } + + @PreAuthorize("hasRole('ROLE_USER')") + @PostMapping(value = "/" + DEVICE + "/verify", + consumes = {"text/html", "application/xhtml+xml","application/xml;q=0.9","image/webp","*/*;q=0.8"}) + public String readUserCode(@RequestParam(USER_CODE) String userCode, + @ModelAttribute("authorizationRequest") AuthorizationRequest authRequest, + Principal p, + HttpServletRequest req, + ModelMap model, + HttpSession session) + { + String result = deviceEndpoint.readUserCode(userCode, model, session); + if (result.equals(APPROVE_DEVICE) && !perunOidcConfig.getTheme().equalsIgnoreCase("default")) { + if (StringUtils.hasText(req.getParameter(ACR))) { + storeAcr(req.getParameter(ACR), userCode); + } + + return themedApproveDevice(model, p, req); + } else if (result.equals(REQUEST_USER_CODE) && !perunOidcConfig.getTheme().equalsIgnoreCase("default")) { + ControllerUtils.setPageOptions(model, req, localization, htmlClasses, perunOidcConfig); + model.put("page", REQUEST_USER_CODE); + return "themedRequestUserCode"; + } + + return result; + } + + @PreAuthorize("hasRole('ROLE_USER')") + @PostMapping(value = "/" + DEVICE + "/approve", params = {USER_CODE, USER_OAUTH_APPROVAL}) + public String approveDevice(@RequestParam(USER_CODE) String userCode, + @RequestParam(USER_OAUTH_APPROVAL) Boolean approve, + @ModelAttribute(USER_OAUTH_APPROVAL) AuthorizationRequest authRequest, + Principal p, + HttpServletRequest req, + ModelMap model, + Authentication auth, + HttpSession session) + { + String result = deviceEndpoint.approveDevice(userCode, approve, model, auth, session); + if (result.equals(DEVICE_APPROVED) && !perunOidcConfig.getTheme().equalsIgnoreCase("default")) { + model.remove("scopes"); + + DeviceCode dc = (DeviceCode)session.getAttribute("deviceCode"); + ClientDetailsEntity client = (ClientDetailsEntity) model.get("client"); + PerunUserInfo user = (PerunUserInfo) userInfoService.getByUsernameAndClientId( + p.getName(), client.getClientId()); + + ControllerUtils.setScopesAndClaims(scopeService, scopeClaimTranslationService, model, dc.getScope(), user); + ControllerUtils.setPageOptions(model, req, localization, htmlClasses, perunOidcConfig); + + model.put("page", DEVICE_APPROVED); + return "themedDeviceApproved"; + } + + return result; + } + + private void storeAcr(String acrValue, String userCode) { + DeviceCodeAcr acr = deviceCodeAcrRepository.getByUserCode(userCode); + acr.setShibAuthnContextClass(acrValue); + long expiresAtEpoch = Instant.now().plusSeconds(600L).toEpochMilli(); + acr.setExpiresAt(expiresAtEpoch); + deviceCodeAcrRepository.store(acr); + } + + private String themedApproveDevice(ModelMap model, Principal p, HttpServletRequest req) { + model.remove("scopes"); + DeviceCode dc = (DeviceCode) model.get("dc"); + ClientDetailsEntity client = (ClientDetailsEntity) model.get("client"); + PerunUserInfo user = (PerunUserInfo) userInfoService.getByUsernameAndClientId( + p.getName(), client.getClientId()); + ControllerUtils.setScopesAndClaims(scopeService, scopeClaimTranslationService, model, dc.getScope(), user); + ControllerUtils.setPageOptions(model, req, localization, htmlClasses, perunOidcConfig); + + model.put("page", APPROVE_DEVICE); + return "themedApproveDevice"; + } + + private void storeAcrBase(String deviceCode, String userCode) { + DeviceCodeAcr acrBase = new DeviceCodeAcr(deviceCode, userCode); + acrBase.setExpiresAt(Instant.now().plusSeconds(1800).toEpochMilli()); + deviceCodeAcrRepository.store(acrBase); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/AupController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/AupController.java new file mode 100644 index 000000000..ac0ccb5b2 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/AupController.java @@ -0,0 +1,162 @@ +package cz.muni.ics.oidc.web.controllers; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import cz.muni.ics.oidc.models.Aup; +import cz.muni.ics.oidc.models.PerunAttribute; +import cz.muni.ics.oidc.models.mappers.RpcMapper; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.web.WebHtmlClasses; +import cz.muni.ics.oidc.web.langs.Localization; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.SessionAttribute; + +/** + * Controller of the AUP page + * + * @author Dominik Baranek <baranek@ics.muni.cz> + */ +@Controller +public class AupController { + + public static final String URL = "aup"; + public static final String NEW_AUPS = "newAups"; + public static final String APPROVED = "approved"; + public static final String RETURN_URL = "returnUrl"; + public static final String USER_ATTR = "userAttr"; + + private static final SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd"); + private static final Logger log = LoggerFactory.getLogger(AupController.class); + + private final JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance; + private final ObjectMapper mapper = new ObjectMapper(); + + @Autowired + private PerunAdapter perunAdapter; + + @Autowired + private PerunOidcConfig perunOidcConfig; + + @Autowired + private Localization localization; + + @Autowired + private WebHtmlClasses htmlClasses; + + @GetMapping(value = "/" + URL) + public String showAup(HttpServletRequest request, Map<String, Object> model, + @SessionAttribute(name = NEW_AUPS) String newAupsString) throws IOException + { + JsonNode newAupsJson = mapper.readTree(newAupsString); + Map<String, Aup> newAups = new LinkedHashMap<>(); + + Iterator<Map.Entry<String, JsonNode>> iterator = newAupsJson.fields(); + while (iterator.hasNext()) { + Map.Entry<String, JsonNode> keyAupPair = iterator.next(); + newAups.put(keyAupPair.getKey(), RpcMapper.mapAup(keyAupPair.getValue())); + } + + model.put(NEW_AUPS, newAups); + ControllerUtils.setPageOptions(model, request, localization, htmlClasses, perunOidcConfig); + + return "aup"; + } + + @PostMapping(value = "/" + URL, consumes = "application/x-www-form-urlencoded") + public String storeAup(HttpServletRequest request, + @SessionAttribute String returnUrl, + @SessionAttribute(name = NEW_AUPS) String newAupsString, + @SessionAttribute(name = USER_ATTR) String userAupsAttrName) throws IOException + { + JsonNode aupsToApproveJson = mapper.readTree(newAupsString); + ObjectNode aupsToApproveJsonObject = new ObjectNode(jsonNodeFactory); + + Iterator<Map.Entry<String, JsonNode>> iterator = aupsToApproveJson.fields(); + while (iterator.hasNext()) { + Map.Entry<String, JsonNode> keyAupPair = iterator.next(); + ObjectNode aup = (ObjectNode) keyAupPair.getValue(); + + Date date = new Date(System.currentTimeMillis()); + aup.put(Aup.SIGNED_ON, formatter.format(date)); + + if (aupsToApproveJsonObject.has(keyAupPair.getKey())) { + aupsToApproveJsonObject.replace(keyAupPair.getKey(), aup); + } else { + aupsToApproveJsonObject.set(keyAupPair.getKey(), aup); + } + } + + Long userId = Long.parseLong(request.getUserPrincipal().getName()); + + try { + PerunAttribute userAupsAttr = perunAdapter.getAdapterRpc().getUserAttribute(userId, userAupsAttrName); + if (userAupsAttr != null) { + Map<String, String> userAupsAttrValue = new LinkedHashMap<>(); + if (userAupsAttr.valueAsMap() != null) { + userAupsAttrValue = userAupsAttr.valueAsMap(); + } + + ObjectNode userAupsAttrAsObjNode = mapper.convertValue(userAupsAttrValue, ObjectNode.class); + + ObjectNode userAttrValueUpdated = updateUserAupsAttrValue(userAupsAttrAsObjNode, aupsToApproveJsonObject); + userAupsAttr.setValue(userAupsAttr.getType(), userAttrValueUpdated); + perunAdapter.getAdapterRpc().setUserAttribute(userId, userAupsAttr); + } + } catch (Exception e) { + log.warn("Exception when storing aup, probably RPC not reachable", e); + } + + request.getSession().removeAttribute(NEW_AUPS); + request.getSession().removeAttribute(RETURN_URL); + request.getSession().removeAttribute(USER_ATTR); + request.getSession().setAttribute(APPROVED, true); + + return "redirect:" + returnUrl; + } + + private ObjectNode updateUserAupsAttrValue(ObjectNode userAups, ObjectNode newAups) throws IOException { + if (userAups == null) { + userAups = new ObjectNode(jsonNodeFactory); + } + + Iterator<Map.Entry<String, JsonNode>> newAupsFields = newAups.fields(); + + while (newAupsFields.hasNext()) { + Map.Entry<String, JsonNode> voNameToListOfAups = newAupsFields.next(); + String aupKey = voNameToListOfAups.getKey(); + ObjectNode newApprovedAup = (ObjectNode) voNameToListOfAups.getValue(); + + ArrayNode oldAupsArray = null; + + if (userAups.get(voNameToListOfAups.getKey()) != null) { + String oldAupsAsString = userAups.get(aupKey).asText(); + oldAupsArray = (ArrayNode) mapper.readTree(oldAupsAsString); + } + + if (oldAupsArray == null) { + oldAupsArray = new ArrayNode(jsonNodeFactory); + } + + oldAupsArray.add(newApprovedAup); + userAups.put(aupKey, oldAupsArray.toString()); + } + + return userAups; + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/ControllerUtils.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/ControllerUtils.java new file mode 100644 index 000000000..861c6f0d3 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/ControllerUtils.java @@ -0,0 +1,304 @@ +package cz.muni.ics.oidc.web.controllers; + +import com.google.common.base.Strings; +import com.google.common.collect.Sets; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import cz.muni.ics.oidc.server.PerunScopeClaimTranslationService; +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.web.WebHtmlClasses; +import cz.muni.ics.oidc.web.langs.Localization; +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; +import javax.servlet.http.HttpServletRequest; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URIBuilder; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.model.UserInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class with common methods used for Controllers. + * + * @author Dominik Frantisek Bucik (bucik@ics.muni.cz) + */ +public class ControllerUtils { + + private static final Logger log = LoggerFactory.getLogger(ControllerUtils.class); + + private static final String LANG_KEY = "lang"; + private static final String REQ_URL_KEY = "reqURL"; + private static final String LANGS_MAP_KEY = "langsMap"; + public static final String LANG_PROPS_KEY = "langProps"; + + /** + * Set language properties for page. + + * @param model model object + * @param req request object + * @param localization localization with texts + */ + public static void setLanguageForPage(Map<String, Object> model, HttpServletRequest req, + Localization localization) { + String langFromParam = req.getParameter(LANG_KEY); + String browserLang = req.getLocale().getLanguage(); + + List<String> enabledLangs = localization.getEnabledLanguages(); + String langKey = "en"; + + if (langFromParam != null + && enabledLangs.stream().anyMatch(x -> x.equalsIgnoreCase(langFromParam))) { + langKey = langFromParam; + } else if (enabledLangs.stream().anyMatch(x -> x.equalsIgnoreCase(browserLang))) { + langKey = browserLang; + } + + String reqUrl = req.getRequestURL().toString(); + + if (!Strings.isNullOrEmpty(req.getQueryString())) { + reqUrl += ('?' + req.getQueryString()); + } + + try { + reqUrl = removeQueryParameter(reqUrl, LANG_KEY); + } catch (URISyntaxException e) { + log.warn("Could not remove lang param"); + } + + Properties langProperties = localization.getLocalizationFiles().get(langKey); + + model.put(LANG_KEY, langKey); + model.put(REQ_URL_KEY, reqUrl); + model.put(LANGS_MAP_KEY, localization.getEntriesAvailable()); + model.put(LANG_PROPS_KEY, langProperties); + } + + /** + * Create redirect URL. + * + * @param request Request object + * @param removedPart Part of URL to be removed + * @param pathPart What to include as Path + * @param params Map object of parameters + * @return Modified redirect URL + */ + public static String createRedirectUrl(HttpServletRequest request, String removedPart, + String pathPart, Map<String, String> params) { + String baseUrl = request.getRequestURL().toString(); + int endIndex = baseUrl.indexOf(removedPart); + if (endIndex > 1) { + baseUrl = baseUrl.substring(0, endIndex); + } + + StringBuilder builder = new StringBuilder(); + builder.append(baseUrl); + builder.append(pathPart); + if (!params.isEmpty()) { + builder.append('?'); + for (Map.Entry<String, String> entry : params.entrySet()) { + try { + String encodedParamVal = + URLEncoder.encode(entry.getValue(), String.valueOf(StandardCharsets.UTF_8)); + builder.append(entry.getKey()); + builder.append('='); + builder.append(encodedParamVal); + builder.append('&'); + } catch (UnsupportedEncodingException e) { + log.warn("Failed to encode param: {}, {}", entry.getKey(), entry.getValue()); + } + } + builder.deleteCharAt(builder.length() - 1); + } + + return builder.toString(); + } + + /** + * Set all options for page. + + * @param model model object + * @param req request object + * @param localization localization with texts + * @param classes additional html classes + * @param perunOidcConfig oidc config class + */ + public static void setPageOptions(Map<String, Object> model, HttpServletRequest req, + Localization localization, + WebHtmlClasses classes, PerunOidcConfig perunOidcConfig) { + setLanguageForPage(model, req, localization); + model.put("classes", classes.getWebHtmlClassesProperties()); + model.put("theme", perunOidcConfig.getTheme().toLowerCase()); + model.put("baseURL", perunOidcConfig.getBaseURL()); + model.put("samlResourcesURL", perunOidcConfig.getSamlResourcesURL()); + model.put("contactMail", perunOidcConfig.getEmailContact()); + } + + /** + * Set scopes and claims for consent page. + + * @param scopeService service for working with scopes + * @param translationService scope to claim translation service + * @param model model object + * @param scope set of scopes + * @param user userInfo object + */ + public static void setScopesAndClaims(SystemScopeService scopeService, + PerunScopeClaimTranslationService translationService, + Map<String, Object> model, + Set<String> scope, + UserInfo user) { + Set<SystemScope> scopes = scopeService.fromStrings(scope); + Set<SystemScope> sortedScopes = new LinkedHashSet<>(scopes.size()); + Set<SystemScope> systemScopes = scopeService.getAll(); + + // sort scopes for display based on the inherent order of system scopes + for (SystemScope s : systemScopes) { + if (scopes.contains(s)) { + sortedScopes.add(s); + } + } + + // add in any scopes that aren't system scopes to the end of the list + sortedScopes.addAll(Sets.difference(scopes, systemScopes)); + + Map<String, Map<String, Object>> claimsForScopes = new LinkedHashMap<>(); + if (user != null) { + JsonObject userJson = user.toJson(); + for (SystemScope systemScope : sortedScopes) { + Map<String, Object> claimValues = new LinkedHashMap<>(); + Set<String> claims = + translationService.getClaimsForScope(systemScope.getValue()); + for (String claim : claims) { + if (userJson.has(claim)) { + JsonElement claimJson = userJson.get(claim); + if (claimJson == null || claimJson.isJsonNull()) { + continue; + } + if (claimJson.isJsonPrimitive()) { + claimValues.put(claim, claimJson.getAsString()); + } else if (claimJson.isJsonArray()) { + JsonArray arr = userJson.getAsJsonArray(claim); + List<String> values = new ArrayList<>(); + for (int i = 0; i < arr.size(); i++) { + values.add(arr.get(i).getAsString()); + } + claimValues.put(claim, values); + } + } + } + claimsForScopes.put(systemScope.getValue(), claimValues); + } + } + + sortedScopes = sortedScopes.stream() + .filter(systemScope -> { + if ("offline_access".equalsIgnoreCase(systemScope.getValue())) { + claimsForScopes.put("offline_access", + Collections.singletonMap("offline_access", true)); + return true; + } + return claimsForScopes.containsKey(systemScope.getValue()); + }) + .sorted((o1, o2) -> compareByClaimsAmount(o1, o2, claimsForScopes)) + .collect(Collectors.toCollection(LinkedHashSet::new)); + model.put("claims", claimsForScopes); + model.put("scopes", sortedScopes); + } + + /** + * Create URL form base and parameters. + + * @param base String with base of the URL + * @param params Map of parameters to be added + * @return constructed URL + */ + public static String createUrl(String base, Map<String, String> params) { + String url = base; + if (!params.isEmpty()) { + url += '?'; + StringBuilder sb = new StringBuilder(url); + Iterator<Map.Entry<String, String>> it = params.entrySet().iterator(); + if (it.hasNext()) { + while (it.hasNext()) { + Map.Entry<String, String> param = it.next(); + try { + if (param.getKey() != null && param.getValue() != null) { + String encodedValue = URLEncoder.encode(param.getValue(), + StandardCharsets.UTF_8.toString()); + sb.append(param.getKey()).append('=').append(encodedValue); + } + } catch (UnsupportedEncodingException e) { + //TODO: handle + } + if (it.hasNext()) { + sb.append('&'); + } + } + url = sb.toString(); + } + } + return url; + } + + /** + * Reconstruct request URL. + + * @param oidcConfig oidc config object + * @param newPath new path to be appended + * @return request URL + */ + public static String constructRequestUrl(PerunOidcConfig oidcConfig, String newPath) { + String url = oidcConfig.getConfigBean().getIssuer(); + newPath = (url.endsWith("/") ? newPath.replaceFirst("/", "") : newPath); + return url + newPath; + } + + private static String removeQueryParameter(String url, String parameterName) + throws URISyntaxException { + URIBuilder uriBuilder = new URIBuilder(url); + List<NameValuePair> queryParameters = uriBuilder.getQueryParams() + .stream() + .filter(p -> !p.getName().equals(parameterName)) + .collect(Collectors.toList()); + if (queryParameters.isEmpty()) { + uriBuilder.removeQuery(); + } else { + uriBuilder.setParameters(queryParameters); + } + return uriBuilder.build().toString(); + } + + private static int compareByClaimsAmount(SystemScope o1, SystemScope o2, + Map<String, Map<String, Object>> claimsForScopes) { + int o1ClaimsSize = claimsForScopes.getOrDefault(o1.getValue(), + new LinkedHashMap<>()).size(); + int o2ClaimsSize = claimsForScopes.getOrDefault(o2.getValue(), + new LinkedHashMap<>()).size(); + int compare = Integer.compare(o1ClaimsSize, o2ClaimsSize); + if (o1ClaimsSize == 0 && compare == 0) { + return 0; + } else if (o1ClaimsSize == 0) { + return 1; + } else if (o2ClaimsSize == 0) { + return -1; + } else { + return compare; + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/IsTestSpController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/IsTestSpController.java new file mode 100644 index 000000000..09b0508a0 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/IsTestSpController.java @@ -0,0 +1,68 @@ +package cz.muni.ics.oidc.web.controllers; + +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_ACCEPTED; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_TARGET; + +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.web.WebHtmlClasses; +import cz.muni.ics.oidc.web.langs.Localization; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * Controller for IS TEST SP pages. + * + * @author Pavol Pluta <pavol.pluta1@gmail.com> + */ +@Controller +public class IsTestSpController { + private static final Logger log = LoggerFactory.getLogger(IsTestSpController.class); + + public static final String MAPPING = "/testRpWarning"; + public static final String IS_TEST_SP_APPROVED_SESS = "isTestSpApprovedSession"; + private static final String TARGET = "target"; + private static final String ACTION = "action"; + + private final Localization localization; + private final WebHtmlClasses htmlClasses; + private final PerunOidcConfig perunOidcConfig; + + @Autowired + public IsTestSpController(Localization localization, WebHtmlClasses htmlClasses, PerunOidcConfig perunOidcConfig) { + this.localization = localization; + this.htmlClasses = htmlClasses; + this.perunOidcConfig = perunOidcConfig; + } + + @GetMapping(value = MAPPING, params = PARAM_TARGET) + public String isTestSpWarning(HttpServletRequest req, + Map<String, Object> model, + @RequestParam(PARAM_TARGET) String returnUrl) + { + log.debug("Display warning page for isTestSp"); + model.put(TARGET, returnUrl); + model.put(ACTION, req.getRequestURL().toString()); + ControllerUtils.setPageOptions(model, req, localization, htmlClasses, perunOidcConfig); + return "isTestSpWarning"; + } + + @GetMapping(value = MAPPING, params = {PARAM_TARGET, PARAM_ACCEPTED}) + public String warningApproved(HttpServletRequest request, + @RequestParam(PARAM_TARGET) String target) + { + log.debug("Warning approved, set session attribute and redirect to {}", target); + HttpSession sess = request.getSession(); + if (sess != null) { + sess.setAttribute(IS_TEST_SP_APPROVED_SESS, true); + } + return "redirect:" + target; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/LoginController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/LoginController.java new file mode 100644 index 000000000..af8c10a5b --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/LoginController.java @@ -0,0 +1,45 @@ +package cz.muni.ics.oidc.web.controllers; + +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.web.WebHtmlClasses; +import cz.muni.ics.oidc.web.langs.Localization; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class LoginController { + + private static final Logger log = LoggerFactory.getLogger(LoginController.class); + + public static final String MAPPING_SUCCESS = "/login_success"; + public static final String MAPPING_FAILURE = "/login_failure"; + + private final Localization localization; + private final WebHtmlClasses htmlClasses; + private final PerunOidcConfig perunOidcConfig; + + @Autowired + public LoginController(PerunOidcConfig perunOidcConfig, Localization localization, WebHtmlClasses htmlClasses) { + this.perunOidcConfig = perunOidcConfig; + this.localization = localization; + this.htmlClasses = htmlClasses; + } + + @RequestMapping(value = MAPPING_SUCCESS) + public String loginSuccess(HttpServletRequest req, Map<String, Object> model) { + ControllerUtils.setPageOptions(model, req, localization, htmlClasses, perunOidcConfig); + return "login_success"; + } + + @RequestMapping(value = MAPPING_FAILURE) + public String loginFailure(HttpServletRequest req, Map<String, Object> model) { + ControllerUtils.setPageOptions(model, req, localization, htmlClasses, perunOidcConfig); + return "login_failure"; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/LogoutController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/LogoutController.java new file mode 100644 index 000000000..07b98fd15 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/LogoutController.java @@ -0,0 +1,38 @@ +package cz.muni.ics.oidc.web.controllers; + +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.web.WebHtmlClasses; +import cz.muni.ics.oidc.web.langs.Localization; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class LogoutController { + + private static final Logger log = LoggerFactory.getLogger(LogoutController.class); + + public static final String MAPPING_SUCCESS = "/logout_success"; + + private final Localization localization; + private final WebHtmlClasses htmlClasses; + private final PerunOidcConfig perunOidcConfig; + + @Autowired + public LogoutController(PerunOidcConfig perunOidcConfig, Localization localization, WebHtmlClasses htmlClasses) { + this.perunOidcConfig = perunOidcConfig; + this.localization = localization; + this.htmlClasses = htmlClasses; + } + + @RequestMapping(value = MAPPING_SUCCESS) + public String logoutSuccess(HttpServletRequest req, Map<String, Object> model) { + ControllerUtils.setPageOptions(model, req, localization, htmlClasses, perunOidcConfig); + return "logout_success"; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunOAuthConfirmationController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunOAuthConfirmationController.java new file mode 100644 index 000000000..64189e0e5 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunOAuthConfirmationController.java @@ -0,0 +1,83 @@ +package cz.muni.ics.oidc.web.controllers; + + +import cz.muni.ics.oidc.server.PerunScopeClaimTranslationService; +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.server.userInfo.PerunUserInfo; +import cz.muni.ics.oidc.web.WebHtmlClasses; +import cz.muni.ics.oidc.web.langs.Localization; +import java.security.Principal; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.oauth2.web.OAuthConfirmationController; +import cz.muni.ics.openid.connect.service.UserInfoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.oauth2.provider.AuthorizationRequest; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.SessionAttributes; + +/** + * Controller of the pages where user accepts that information + * about him will be sent to the client. + * + * @author Dominik František Bučík <bucik@ics.muni.cz> + * @author Peter Jancus <jancus@ics.muni.cz> + */ +@Controller +@SessionAttributes("authorizationRequest") +public class PerunOAuthConfirmationController{ + + public static final String APPROVE = "approve"; + + private final OAuthConfirmationController oAuthConfirmationController; + private final UserInfoService userInfoService; + private final PerunOidcConfig perunOidcConfig; + private final SystemScopeService scopeService; + private final PerunScopeClaimTranslationService scopeClaimTranslationService; + private final Localization localization; + private final WebHtmlClasses htmlClasses; + + @Autowired + public PerunOAuthConfirmationController(OAuthConfirmationController oAuthConfirmationController, + UserInfoService userInfoService, + PerunOidcConfig perunOidcConfig, + SystemScopeService scopeService, + PerunScopeClaimTranslationService scopeClaimTranslationService, + Localization localization, + WebHtmlClasses htmlClasses) + { + this.oAuthConfirmationController = oAuthConfirmationController; + this.userInfoService = userInfoService; + this.perunOidcConfig = perunOidcConfig; + this.scopeService = scopeService; + this.scopeClaimTranslationService = scopeClaimTranslationService; + this.localization = localization; + this.htmlClasses = htmlClasses; + } + + @RequestMapping(value = "/oauth/confirm_access", params = { "client_id" }) + public String confirmAccess(Map<String, Object> model, HttpServletRequest req, Principal p) + { + AuthorizationRequest authRequest = (AuthorizationRequest)model.get("authorizationRequest"); + String result = oAuthConfirmationController.confirmAccess(model, p); + if (result.equals(APPROVE) && !perunOidcConfig.getTheme().equalsIgnoreCase("default")) { + model.remove("scopes"); + model.remove("claims"); + ClientDetailsEntity client = (ClientDetailsEntity) model.get("client"); + PerunUserInfo user = (PerunUserInfo) userInfoService.getByUsernameAndClientId( + p.getName(), client.getClientId()); + ControllerUtils.setScopesAndClaims(scopeService, scopeClaimTranslationService, model, authRequest.getScope(), + user); + ControllerUtils.setPageOptions(model, req, localization, htmlClasses, perunOidcConfig); + + model.put("page", "consent"); + return "themedApprove"; + } + + return result; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunUnapprovedController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunUnapprovedController.java new file mode 100644 index 000000000..bf8fc06ca --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunUnapprovedController.java @@ -0,0 +1,287 @@ +package cz.muni.ics.oidc.web.controllers; + +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_CLIENT_ID; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_HEADER; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_MESSAGE; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_REASON; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_TARGET; +import static cz.muni.ics.oidc.web.controllers.ControllerUtils.LANG_PROPS_KEY; + +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.web.WebHtmlClasses; +import cz.muni.ics.oidc.web.langs.Localization; +import java.util.Map; +import java.util.Properties; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * Ctonroller for the unapproved page. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@Controller +public class PerunUnapprovedController { + + private final static Logger log = LoggerFactory.getLogger(PerunUnapprovedController.class); + + public static final String UNAPPROVED_MAPPING = "/unapproved"; + public static final String UNAPPROVED_SPECIFIC_MAPPING = "/unapproved_spec"; + public static final String UNAPPROVED_IS_CESNET_ELIGIBLE_MAPPING = "/unapprovedIce"; + public static final String UNAPPROVED_ENSURE_VO_MAPPING = "/unapprovedEnsureVo"; + public static final String UNAPPROVED_AUTHORIZATION = "/unapprovedAuthorization"; + public static final String UNAPPROVED_NOT_IN_TEST_VOS_GROUPS = "/unapprovedNotInTestVosGroups"; + public static final String UNAPPROVED_NOT_IN_PROD_VOS_GROUPS = "/unapprovedNotInProdVosGroups"; + public static final String UNAPPROVED_NOT_IN_MANDATORY_VOS_GROUPS = "/unapprovedNotInMandatoryVosGroups"; + public static final String UNAPPROVED_NOT_LOGGED_IN = "/unapprovedNotLoggedIn"; + + public static final String REASON_NOT_SET = "notSet"; + public static final String REASON_EXPIRED = "expired"; + + private static final String OUT_HEADER = "outHeader"; + private static final String OUT_MESSAGE = "outMessage"; + private static final String OUT_CONTACT_P = "outContactP"; + + private static final String ENSURE_VO_HDR = "403_ensure_vo_hdr"; + private static final String ENSURE_VO_MSG = "403_ensure_vo_msg"; + + private static final String AUTHORIZATION_HDR = "403_authorization_hdr"; + private static final String AUTHORIZATION_MSG = "403_authorization_msg"; + + private static final String ICE_NOT_SET_HDR = "403_isCesnetEligible_notSet_hdr"; + private static final String ICE_NOT_SET_MSG = "403_isCesnetEligible_notSet_msg"; + private static final String ICE_EXPIRED_HDR = "403_isCesnetEligible_expired_hdr"; + private static final String ICE_EXPIRED_MSG = "403_isCesnetEligible_expired_msg"; + + private static final String NOT_IN_TEST_VOS_GROUPS_HDR = "403_not_in_test_vos_groups_hdr"; + private static final String NOT_IN_TEST_VOS_GROUPS_MSG = "403_not_in_test_vos_groups_msg"; + + private static final String NOT_IN_PROD_VOS_GROUPS_HDR = "403_not_in_prod_vos_groups_hdr"; + private static final String NOT_IN_PROD_VOS_GROUPS_MSG = "403_not_in_prod_vos_groups_msg"; + + private static final String NOT_IN_MANDATORY_VOS_GROUPS_HDR = "403_not_in_mandatory_vos_groups_hdr"; + private static final String NOT_IN_MANDATORY_VOS_GROUPS_MSG = "403_not_in_mandatory_vos_groups_msg"; + + private static final String NOT_LOGGED_IN_HDR = "403_not_logged_in_hdr"; + private static final String NOT_LOGGED_IN_MSG = "403_not_logged_in_msg"; + + private static final String CONTACT_PLACEHOLDER = "%%CONTACT_EMAIL%%"; + private static final String TARGET_URL_PLACEHOLDER = "%%TARGET%%"; + private static final String CONTACT_LANG_PROP_KEY = "contact_p"; + private static final String CONTACT_MAIL = "contactMail"; + + @Autowired + private ClientDetailsEntityService clientService; + + @Autowired + private PerunOidcConfig perunOidcConfig; + + @Autowired + private Localization localization; + + @Autowired + private WebHtmlClasses htmlClasses; + + @GetMapping(value = UNAPPROVED_MAPPING) + public String showUnapproved(ServletRequest req, Map<String, Object> model, + @RequestParam(PARAM_CLIENT_ID) String clientId) { + HttpServletRequest request = (HttpServletRequest) req; + ClientDetailsEntity client; + + try { + client = clientService.loadClientByClientId(clientId); + } catch (OAuth2Exception e) { + log.error("showUnapproved: OAuth2Exception was thrown when attempting to load client", e); + model.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + } catch (IllegalArgumentException e) { + log.error("showUnapproved: IllegalArgumentException was thrown when attempting to load client", e); + model.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); + return HttpCodeView.VIEWNAME; + } + + if (client == null) { + log.error("showUnapproved: could not find client " + clientId); + model.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + } + + ControllerUtils.setPageOptions(model, request, localization, htmlClasses, perunOidcConfig); + model.put("client", client); + + return "unapproved"; + } + + @GetMapping(value = UNAPPROVED_SPECIFIC_MAPPING) + public String showUnapprovedSpec(ServletRequest req, Map<String, Object> model, + @RequestParam(value = PARAM_HEADER, required = false) String header, + @RequestParam(value = PARAM_MESSAGE, required = false) String message) { + + ControllerUtils.setPageOptions(model, (HttpServletRequest) req, localization, htmlClasses, perunOidcConfig); + + String headerText = getText(model, header); + String messageText = getText(model, message); + String contactPText = getText(model, CONTACT_LANG_PROP_KEY); + + model.put(OUT_HEADER, headerText); + model.put(OUT_MESSAGE, messageText); + model.put(OUT_CONTACT_P, contactPText); + model.put(CONTACT_MAIL, perunOidcConfig.getEmailContact()); + + return "unapproved_spec"; + } + + @GetMapping(value = UNAPPROVED_IS_CESNET_ELIGIBLE_MAPPING) + public String showUnapprovedIsCesnetEligible(ServletRequest req, Map<String, Object> model, + @RequestParam(value = PARAM_TARGET) String target, + @RequestParam(value = PARAM_REASON) String reason) { + + ControllerUtils.setPageOptions(model, (HttpServletRequest) req, localization, htmlClasses, perunOidcConfig); + + String header; + String message; + String contactPText = getText(model, CONTACT_LANG_PROP_KEY); + + if (REASON_EXPIRED.equals(reason)) { + header = getText(model, ICE_EXPIRED_HDR); + message = getText(model, ICE_EXPIRED_MSG); + } else if (REASON_NOT_SET.equals(reason)){ + header = getText(model, ICE_NOT_SET_HDR); + message = getText(model, ICE_NOT_SET_MSG); + } else { + model.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + } + + header = replace(header, TARGET_URL_PLACEHOLDER, target); + message = replace(message, TARGET_URL_PLACEHOLDER, target); + + model.put(OUT_HEADER, header); + model.put(OUT_MESSAGE, message); + model.put(OUT_CONTACT_P, contactPText); + model.put(CONTACT_MAIL, perunOidcConfig.getEmailContact()); + + return "unapproved_spec"; + } + + @GetMapping(value = UNAPPROVED_ENSURE_VO_MAPPING) + public String showUnapprovedEnsureVo(ServletRequest req, Map<String, Object> model) { + ControllerUtils.setPageOptions(model, (HttpServletRequest) req, localization, htmlClasses, perunOidcConfig); + + String header = getText(model, ENSURE_VO_HDR); + String message = getText(model, ENSURE_VO_MSG); + String contactPText = getText(model, CONTACT_LANG_PROP_KEY); + + model.put(OUT_HEADER, header); + model.put(OUT_MESSAGE, message); + model.put(OUT_CONTACT_P, contactPText); + model.put(CONTACT_MAIL, perunOidcConfig.getEmailContact()); + + return "unapproved_spec"; + } + + @GetMapping(value = UNAPPROVED_AUTHORIZATION) + public String showUnapprovedAuthorization(ServletRequest req, Map<String, Object> model) { + ControllerUtils.setPageOptions(model, (HttpServletRequest) req, localization, htmlClasses, perunOidcConfig); + + String header = getText(model, AUTHORIZATION_HDR); + String message = getText(model, AUTHORIZATION_MSG); + String contactPText = getText(model, CONTACT_LANG_PROP_KEY); + + model.put(OUT_HEADER, header); + model.put(OUT_MESSAGE, message); + model.put(OUT_CONTACT_P, contactPText); + model.put(CONTACT_MAIL, perunOidcConfig.getEmailContact()); + + return "unapproved_spec"; + } + + @GetMapping(value = UNAPPROVED_NOT_IN_TEST_VOS_GROUPS) + public String showUnapprovedNotInTestVosGroups(ServletRequest req, Map<String, Object> model) { + ControllerUtils.setPageOptions(model, (HttpServletRequest) req, localization, htmlClasses, perunOidcConfig); + + String header = getText(model, NOT_IN_TEST_VOS_GROUPS_HDR); + String message = getText(model, NOT_IN_TEST_VOS_GROUPS_MSG); + String contactPText = getText(model, CONTACT_LANG_PROP_KEY); + + model.put(OUT_HEADER, header); + model.put(OUT_MESSAGE, message); + model.put(OUT_CONTACT_P, contactPText); + model.put(CONTACT_MAIL, perunOidcConfig.getEmailContact()); + + return "unapproved_spec"; + } + + @GetMapping(value = UNAPPROVED_NOT_IN_PROD_VOS_GROUPS) + public String showUnapprovedNotInProdVosGroups(ServletRequest req, Map<String, Object> model) { + ControllerUtils.setPageOptions(model, (HttpServletRequest) req, localization, htmlClasses, perunOidcConfig); + + String header = getText(model, NOT_IN_PROD_VOS_GROUPS_HDR); + String message = getText(model, NOT_IN_PROD_VOS_GROUPS_MSG); + String contactPText = getText(model, CONTACT_LANG_PROP_KEY); + + model.put(OUT_HEADER, header); + model.put(OUT_MESSAGE, message); + model.put(OUT_CONTACT_P, contactPText); + model.put(CONTACT_MAIL, perunOidcConfig.getEmailContact()); + + return "unapproved_spec"; + } + + @GetMapping(value = UNAPPROVED_NOT_IN_MANDATORY_VOS_GROUPS) + public String showUnapprovedNotInMandatoryVosGroups(ServletRequest req, Map<String, Object> model) { + ControllerUtils.setPageOptions(model, (HttpServletRequest) req, localization, htmlClasses, perunOidcConfig); + + String header = getText(model, NOT_IN_MANDATORY_VOS_GROUPS_HDR); + String message = getText(model, NOT_IN_MANDATORY_VOS_GROUPS_MSG); + String contactPText = getText(model, CONTACT_LANG_PROP_KEY); + + model.put(OUT_HEADER, header); + model.put(OUT_MESSAGE, message); + model.put(OUT_CONTACT_P, contactPText); + model.put(CONTACT_MAIL, perunOidcConfig.getEmailContact()); + + return "unapproved_spec"; + } + + @GetMapping(value = UNAPPROVED_NOT_LOGGED_IN) + public String showUnapprovedNotLoggedIn(ServletRequest req, Map<String, Object> model) { + ControllerUtils.setPageOptions(model, (HttpServletRequest) req, localization, htmlClasses, perunOidcConfig); + + String header = getText(model, NOT_LOGGED_IN_HDR); + String message = getText(model, NOT_LOGGED_IN_MSG); + String contactPText = getText(model, CONTACT_LANG_PROP_KEY); + + model.put(OUT_HEADER, header); + model.put(OUT_MESSAGE, message); + model.put(OUT_CONTACT_P, contactPText); + model.put(CONTACT_MAIL, perunOidcConfig.getEmailContact()); + + return "unapproved_spec"; + } + + private String getText(Map<String, Object> model, String key) { + Properties langProps = (Properties) model.get(LANG_PROPS_KEY); + return langProps.getProperty(key); + } + + private String replace(String container, String key, String value) { + if (container.contains(key)) { + return container.replaceAll(key, value); + } else { + return container; + } + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunUnapprovedRegistrationController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunUnapprovedRegistrationController.java new file mode 100644 index 000000000..0744659b5 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunUnapprovedRegistrationController.java @@ -0,0 +1,182 @@ +package cz.muni.ics.oidc.web.controllers; + +import cz.muni.ics.oidc.models.Facility; +import cz.muni.ics.oidc.models.Group; +import cz.muni.ics.oidc.models.PerunAttributeValue; +import cz.muni.ics.oidc.models.Vo; +import cz.muni.ics.oidc.server.adapters.PerunAdapter; +import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig; +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.web.WebHtmlClasses; +import cz.muni.ics.oidc.web.langs.Localization; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * Controller for the unapproved page which offers registration. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@Controller +public class PerunUnapprovedRegistrationController { + + private final static Logger log = LoggerFactory.getLogger(PerunUnapprovedRegistrationController.class); + + public static final String REGISTRATION_FORM_MAPPING = "/regForm"; + public static final String REGISTRATION_FORM_SUBMIT_MAPPING = "/regForm/submit"; + public static final String REGISTRATION_CONTINUE_MAPPING = "/regForm/continue"; + + @Autowired + private ClientDetailsEntityService clientService; + + @Autowired + private PerunAdapter perunAdapter; + + @Autowired + private FacilityAttrsConfig facilityAttrsConfig; + + @Autowired + private PerunOidcConfig perunOidcConfig; + + @Autowired + private Localization localization; + + @Autowired + private WebHtmlClasses htmlClasses; + + @GetMapping(value = REGISTRATION_FORM_MAPPING) + public String showRegistrationForm(Map<String, Object> model, ServletRequest req, ServletResponse res, + @RequestParam("client_id") String clientId, + @RequestParam("facility_id") Long facilityId, + @RequestParam("user_id") Long userId) { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + ClientDetailsEntity client; + + try { + client = clientService.loadClientByClientId(clientId); + } catch (OAuth2Exception e) { + log.error("confirmAccess: OAuth2Exception was thrown when attempting to load client", e); + model.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + } catch (IllegalArgumentException e) { + log.error("confirmAccess: IllegalArgumentException was thrown when attempting to load client", e); + model.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); + return HttpCodeView.VIEWNAME; + } + + if (client == null) { + log.error("confirmAccess: could not find client {}", clientId); + model.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + } + + Facility facility = perunAdapter.getFacilityByClientId(clientId); + Map<String, PerunAttributeValue> facilityAttributes = perunAdapter.getFacilityAttributeValues(facility, + facilityAttrsConfig.getMembershipAttrNames()); + List<String> voShortNames = facilityAttributes.get(facilityAttrsConfig.getVoShortNamesAttr()).valueAsList(); + Map<Vo, List<Group>> groupsForRegistration = perunAdapter.getAdapterRpc() + .getGroupsForRegistration(facility, userId, voShortNames); + log.debug("groupsForReg: {}", groupsForRegistration); + + if (groupsForRegistration.isEmpty()) { + String redirectUrl = ControllerUtils.createRedirectUrl(request, REGISTRATION_FORM_MAPPING, + PerunUnapprovedController.UNAPPROVED_MAPPING, Collections.singletonMap("client_id", clientId)); + response.reset(); + response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + response.setHeader("Location", redirectUrl); + return null; + } else if (groupsForRegistration.keySet().size() == 1) { + for (Map.Entry<Vo, List<Group>> entry: groupsForRegistration.entrySet()) { + // no other way how to extract the first item (as it is the only) + List<Group> groupList = groupsForRegistration.get(entry.getKey()); + if (groupList.size() == 1) { + Group group = groupList.get(0); + String redirectUrl = createRegistrarUrl(entry.getKey(), group.getName()); + response.reset(); + response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + response.setHeader("Location", redirectUrl); + return null; + } + } + } + + ControllerUtils.setPageOptions(model, request, localization, htmlClasses, perunOidcConfig); + model.put("client", client); + model.put("facilityId", facilityId); + model.put("action", buildActionUrl(request)); + model.put("groupsForRegistration", groupsForRegistration); + model.put("page", "regForm"); + + return "registrationForm"; + } + + @GetMapping(value = REGISTRATION_FORM_SUBMIT_MAPPING) + public void processRegistrationForm(@RequestParam("selectedGroup") String groupName, + @RequestParam("selectedVo") String voName, + ServletResponse res) throws IOException { + HttpServletResponse request = (HttpServletResponse) res; + + groupName = groupName.split(":", 2)[1]; + + String redirectUrl = createRegistrarUrl(voName, groupName); + + request.sendRedirect(redirectUrl); + } + + @GetMapping(value = REGISTRATION_CONTINUE_MAPPING) + public String showContinuePage(Map<String, Object> model, ServletRequest req, + @RequestParam("client_id") String clientId, + @RequestParam("facility_id") Long facilityId, + @RequestParam("user_id") Long userId) { + HttpServletRequest request = (HttpServletRequest) req; + + model.put("page", "regContinue"); + model.put("client_id", clientId); + model.put("facility_id", facilityId); + model.put("user_id", userId); + model.put("action", request.getRequestURL().toString() + .replace(REGISTRATION_CONTINUE_MAPPING, REGISTRATION_FORM_MAPPING)); + ControllerUtils.setPageOptions(model, request, localization, htmlClasses, perunOidcConfig); + + return "registrationFormContinue"; + } + + private String createRegistrarUrl(Vo vo, String groupName) { + return createRegistrarUrl(vo.getShortName(), groupName); + } + + private String createRegistrarUrl(String vohortName, String groupName) { + String redirectUrl = perunOidcConfig.getRegistrarUrl().concat("?vo=").concat(vohortName); + if (groupName != null && !groupName.isEmpty() && !groupName.equalsIgnoreCase("members")) { + redirectUrl = redirectUrl.concat("&group=").concat(groupName); + } + + return redirectUrl; + } + + private String buildActionUrl(HttpServletRequest request) { + int startIndex = request.getRequestURL().lastIndexOf(REGISTRATION_FORM_MAPPING); + int length = request.getRequestURL().length(); + return request.getRequestURL().delete(startIndex, length) + .append(REGISTRATION_FORM_SUBMIT_MAPPING).toString(); + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/RegistrationController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/RegistrationController.java new file mode 100644 index 000000000..c75dbfb72 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/RegistrationController.java @@ -0,0 +1,47 @@ +package cz.muni.ics.oidc.web.controllers; + +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.web.WebHtmlClasses; +import cz.muni.ics.oidc.web.langs.Localization; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * Controller for the unapproved page which offers registration. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@Controller +public class RegistrationController { + + private final static Logger log = LoggerFactory.getLogger(RegistrationController.class); + + public static final String PARAM_TARGET = "target"; + + public static final String CONTINUE_DIRECT_MAPPING = "/continueDirect"; + + @Autowired + private PerunOidcConfig perunOidcConfig; + + @Autowired + private Localization localization; + + @Autowired + private WebHtmlClasses htmlClasses; + + @GetMapping(value = CONTINUE_DIRECT_MAPPING, params = { PARAM_TARGET }) + public String showRegistrationForm(Map<String, Object> model, HttpServletRequest req, + @RequestParam(PARAM_TARGET) String target) + { + model.put(PARAM_TARGET, target); + ControllerUtils.setPageOptions(model, req, localization, htmlClasses, perunOidcConfig); + return "continue_direct"; + } + +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/langs/Localization.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/langs/Localization.java new file mode 100644 index 000000000..8af48345c --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/langs/Localization.java @@ -0,0 +1,105 @@ +package cz.muni.ics.oidc.web.langs; + +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Static utility class for Language Bar displayed on custom pages. + * + * It contains mapping with language keys to language displayed names. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +public class Localization { + + private static final Logger log = LoggerFactory.getLogger(Localization.class); + + private Map<String, String> localizationEntries; + private Map<String, Properties> localizationFiles; + private final String localizationFilesPath; + private final List<String> enabledLanguages; + + public Localization(PerunOidcConfig perunOidcConfig) { + this.enabledLanguages = perunOidcConfig.getAvailableLangs(); + this.localizationFilesPath = perunOidcConfig.getLocalizationFilesPath(); + this.initEntriesAndFiles(); + } + + public Map<String, String> getLocalizationEntries() { + return localizationEntries; + } + + public Map<String, Properties> getLocalizationFiles() { + return localizationFiles; + } + + public List<String> getEnabledLanguages() { + return enabledLanguages; + } + + /** + * Get mapping for the languages available + * @return Map with key = language code, value = language displayed text + */ + public Map<String, String> getEntriesAvailable() { + Map<String, String> result = new HashMap<>(); + + for (String key: enabledLanguages) { + String lower = key.toLowerCase(); + if (localizationEntries.containsKey(lower)) { + result.put(lower, localizationEntries.get(lower)); + } + } + + return result; + } + + private void initEntriesAndFiles() { + localizationEntries = new HashMap<>(); + localizationEntries.put("en", "English"); + localizationEntries.put("cs", "Čeština"); + localizationEntries.put("sk", "Slovenčina"); + + localizationFiles = new HashMap<>(); + for (String lang: enabledLanguages) { + lang = lang.toLowerCase(); + if (! localizationEntries.containsKey(lang)) { + continue; + } + + Properties langProps = new Properties(); + String resourceFileName = "localization/" + lang + ".properties"; + try (InputStreamReader isr = new InputStreamReader(Objects.requireNonNull( + getClass().getClassLoader().getResourceAsStream(resourceFileName)), StandardCharsets.UTF_8)) { + langProps.load(isr); + log.debug("Loaded localization file: {}", resourceFileName); + localizationFiles.put(lang, langProps); + } catch (IOException e) { + log.warn("Exception caught when reading {}", resourceFileName, e); + } + + String customFileName = localizationFilesPath + '/' +lang + ".properties"; + try (InputStreamReader isr = new InputStreamReader( + new FileInputStream(customFileName), StandardCharsets.UTF_8 + )) { + langProps.load(isr); + log.debug("Loaded localization file: {}", customFileName); + } catch (FileNotFoundException e) { + log.warn("File: {} not found", customFileName, e); + } catch (IOException e) { + log.warn("Exception caught when reading {}", customFileName, e); + } + } + } +} diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/ClientDetailsEntityJsonProcessor.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/ClientDetailsEntityJsonProcessor.java similarity index 53% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/ClientDetailsEntityJsonProcessor.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/ClientDetailsEntityJsonProcessor.java index 6cb1b712a..a5a91f465 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/ClientDetailsEntityJsonProcessor.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/ClientDetailsEntityJsonProcessor.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect; +package cz.muni.ics.openid.connect; import com.google.common.base.Joiner; @@ -31,65 +31,59 @@ import com.google.gson.JsonParser; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.JWTParser; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.ClientDetailsEntity.AppType; -import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod; -import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType; -import org.mitre.oauth2.model.RegisteredClient; +import cz.muni.ics.util.JsonUtils; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.AppType; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.AuthMethod; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.SubjectType; +import cz.muni.ics.oauth2.model.RegisteredClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.ParseException; -import static org.mitre.oauth2.model.RegisteredClientFields.APPLICATION_TYPE; -import static org.mitre.oauth2.model.RegisteredClientFields.CLAIMS_REDIRECT_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID_ISSUED_AT; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_NAME; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_SECRET; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_SECRET_EXPIRES_AT; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.CODE_CHALLENGE_METHOD; -import static org.mitre.oauth2.model.RegisteredClientFields.CONTACTS; -import static org.mitre.oauth2.model.RegisteredClientFields.DEFAULT_ACR_VALUES; -import static org.mitre.oauth2.model.RegisteredClientFields.DEFAULT_MAX_AGE; -import static org.mitre.oauth2.model.RegisteredClientFields.GRANT_TYPES; -import static org.mitre.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ENC; -import static org.mitre.oauth2.model.RegisteredClientFields.ID_TOKEN_SIGNED_RESPONSE_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.INITIATE_LOGIN_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.JWKS; -import static org.mitre.oauth2.model.RegisteredClientFields.JWKS_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.POLICY_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.POST_LOGOUT_REDIRECT_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.REDIRECT_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.REGISTRATION_ACCESS_TOKEN; -import static org.mitre.oauth2.model.RegisteredClientFields.REGISTRATION_CLIENT_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.REQUEST_OBJECT_SIGNING_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.REQUEST_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.REQUIRE_AUTH_TIME; -import static org.mitre.oauth2.model.RegisteredClientFields.RESPONSE_TYPES; -import static org.mitre.oauth2.model.RegisteredClientFields.SCOPE; -import static org.mitre.oauth2.model.RegisteredClientFields.SCOPE_SEPARATOR; -import static org.mitre.oauth2.model.RegisteredClientFields.SECTOR_IDENTIFIER_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.SOFTWARE_ID; -import static org.mitre.oauth2.model.RegisteredClientFields.SOFTWARE_STATEMENT; -import static org.mitre.oauth2.model.RegisteredClientFields.SOFTWARE_VERSION; -import static org.mitre.oauth2.model.RegisteredClientFields.SUBJECT_TYPE; -import static org.mitre.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_METHOD; -import static org.mitre.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_SIGNING_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.TOS_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ENC; -import static org.mitre.oauth2.model.RegisteredClientFields.USERINFO_SIGNED_RESPONSE_ALG; -import static org.mitre.util.JsonUtils.getAsArray; -import static org.mitre.util.JsonUtils.getAsDate; -import static org.mitre.util.JsonUtils.getAsJweAlgorithm; -import static org.mitre.util.JsonUtils.getAsJweEncryptionMethod; -import static org.mitre.util.JsonUtils.getAsJwsAlgorithm; -import static org.mitre.util.JsonUtils.getAsPkceAlgorithm; -import static org.mitre.util.JsonUtils.getAsString; -import static org.mitre.util.JsonUtils.getAsStringSet; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.APPLICATION_TYPE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLAIMS_REDIRECT_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_ID; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_ID_ISSUED_AT; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_NAME; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_SECRET; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_SECRET_EXPIRES_AT; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CODE_CHALLENGE_METHOD; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CONTACTS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.DEFAULT_ACR_VALUES; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.DEFAULT_MAX_AGE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.GRANT_TYPES; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ENC; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.ID_TOKEN_SIGNED_RESPONSE_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.INITIATE_LOGIN_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.JWKS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.JWKS_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.POLICY_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.POST_LOGOUT_REDIRECT_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REDIRECT_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REGISTRATION_ACCESS_TOKEN; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REGISTRATION_CLIENT_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REQUEST_OBJECT_SIGNING_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REQUEST_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REQUIRE_AUTH_TIME; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.RESPONSE_TYPES; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SCOPE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SCOPE_SEPARATOR; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SECTOR_IDENTIFIER_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SOFTWARE_ID; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SOFTWARE_STATEMENT; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SOFTWARE_VERSION; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SUBJECT_TYPE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_METHOD; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_SIGNING_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.TOS_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ENC; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.USERINFO_SIGNED_RESPONSE_ALG; +import static cz.muni.ics.util.JsonUtils.getAsArray; /** * Utility class to handle the parsing and serialization of ClientDetails objects. @@ -114,31 +108,31 @@ public class ClientDetailsEntityJsonProcessor { ClientDetailsEntity c = new ClientDetailsEntity(); // these two fields should only be sent in the update request, and MUST match existing values - c.setClientId(getAsString(o, CLIENT_ID)); - c.setClientSecret(getAsString(o, CLIENT_SECRET)); + c.setClientId(JsonUtils.getAsString(o, CLIENT_ID)); + c.setClientSecret(JsonUtils.getAsString(o, CLIENT_SECRET)); // OAuth DynReg - c.setRedirectUris(getAsStringSet(o, REDIRECT_URIS)); - c.setClientName(getAsString(o, CLIENT_NAME)); - c.setClientUri(getAsString(o, CLIENT_URI)); - c.setContacts(getAsStringSet(o, CONTACTS)); - c.setTosUri(getAsString(o, TOS_URI)); + c.setRedirectUris(JsonUtils.getAsStringSet(o, REDIRECT_URIS)); + c.setClientName(JsonUtils.getAsString(o, CLIENT_NAME)); + c.setClientUri(JsonUtils.getAsString(o, CLIENT_URI)); + c.setContacts(JsonUtils.getAsStringSet(o, CONTACTS)); + c.setTosUri(JsonUtils.getAsString(o, TOS_URI)); - String authMethod = getAsString(o, TOKEN_ENDPOINT_AUTH_METHOD); + String authMethod = JsonUtils.getAsString(o, TOKEN_ENDPOINT_AUTH_METHOD); if (authMethod != null) { c.setTokenEndpointAuthMethod(AuthMethod.getByValue(authMethod)); } // scope is a space-separated string - String scope = getAsString(o, SCOPE); + String scope = JsonUtils.getAsString(o, SCOPE); if (scope != null) { c.setScope(Sets.newHashSet(Splitter.on(SCOPE_SEPARATOR).split(scope))); } - c.setGrantTypes(getAsStringSet(o, GRANT_TYPES)); - c.setResponseTypes(getAsStringSet(o, RESPONSE_TYPES)); - c.setPolicyUri(getAsString(o, POLICY_URI)); - c.setJwksUri(getAsString(o, JWKS_URI)); + c.setGrantTypes(JsonUtils.getAsStringSet(o, GRANT_TYPES)); + c.setResponseTypes(JsonUtils.getAsStringSet(o, RESPONSE_TYPES)); + c.setPolicyUri(JsonUtils.getAsString(o, POLICY_URI)); + c.setJwksUri(JsonUtils.getAsString(o, JWKS_URI)); JsonElement jwksEl = o.get(JWKS); if (jwksEl != null && jwksEl.isJsonObject()) { @@ -152,29 +146,29 @@ public class ClientDetailsEntityJsonProcessor { } // OIDC Additions - String appType = getAsString(o, APPLICATION_TYPE); + String appType = JsonUtils.getAsString(o, APPLICATION_TYPE); if (appType != null) { c.setApplicationType(AppType.getByValue(appType)); } - c.setSectorIdentifierUri(getAsString(o, SECTOR_IDENTIFIER_URI)); + c.setSectorIdentifierUri(JsonUtils.getAsString(o, SECTOR_IDENTIFIER_URI)); - String subjectType = getAsString(o, SUBJECT_TYPE); + String subjectType = JsonUtils.getAsString(o, SUBJECT_TYPE); if (subjectType != null) { c.setSubjectType(SubjectType.getByValue(subjectType)); } - c.setRequestObjectSigningAlg(getAsJwsAlgorithm(o, REQUEST_OBJECT_SIGNING_ALG)); + c.setRequestObjectSigningAlg(JsonUtils.getAsJwsAlgorithm(o, REQUEST_OBJECT_SIGNING_ALG)); - c.setUserInfoSignedResponseAlg(getAsJwsAlgorithm(o, USERINFO_SIGNED_RESPONSE_ALG)); - c.setUserInfoEncryptedResponseAlg(getAsJweAlgorithm(o, USERINFO_ENCRYPTED_RESPONSE_ALG)); - c.setUserInfoEncryptedResponseEnc(getAsJweEncryptionMethod(o, USERINFO_ENCRYPTED_RESPONSE_ENC)); + c.setUserInfoSignedResponseAlg(JsonUtils.getAsJwsAlgorithm(o, USERINFO_SIGNED_RESPONSE_ALG)); + c.setUserInfoEncryptedResponseAlg(JsonUtils.getAsJweAlgorithm(o, USERINFO_ENCRYPTED_RESPONSE_ALG)); + c.setUserInfoEncryptedResponseEnc(JsonUtils.getAsJweEncryptionMethod(o, USERINFO_ENCRYPTED_RESPONSE_ENC)); - c.setIdTokenSignedResponseAlg(getAsJwsAlgorithm(o, ID_TOKEN_SIGNED_RESPONSE_ALG)); - c.setIdTokenEncryptedResponseAlg(getAsJweAlgorithm(o, ID_TOKEN_ENCRYPTED_RESPONSE_ALG)); - c.setIdTokenEncryptedResponseEnc(getAsJweEncryptionMethod(o, ID_TOKEN_ENCRYPTED_RESPONSE_ENC)); + c.setIdTokenSignedResponseAlg(JsonUtils.getAsJwsAlgorithm(o, ID_TOKEN_SIGNED_RESPONSE_ALG)); + c.setIdTokenEncryptedResponseAlg(JsonUtils.getAsJweAlgorithm(o, ID_TOKEN_ENCRYPTED_RESPONSE_ALG)); + c.setIdTokenEncryptedResponseEnc(JsonUtils.getAsJweEncryptionMethod(o, ID_TOKEN_ENCRYPTED_RESPONSE_ENC)); - c.setTokenEndpointAuthSigningAlg(getAsJwsAlgorithm(o, TOKEN_ENDPOINT_AUTH_SIGNING_ALG)); + c.setTokenEndpointAuthSigningAlg(JsonUtils.getAsJwsAlgorithm(o, TOKEN_ENDPOINT_AUTH_SIGNING_ALG)); if (o.has(DEFAULT_MAX_AGE)) { if (o.get(DEFAULT_MAX_AGE).isJsonPrimitive()) { @@ -188,20 +182,20 @@ public class ClientDetailsEntityJsonProcessor { } } - c.setDefaultACRvalues(getAsStringSet(o, DEFAULT_ACR_VALUES)); - c.setInitiateLoginUri(getAsString(o, INITIATE_LOGIN_URI)); - c.setPostLogoutRedirectUris(getAsStringSet(o, POST_LOGOUT_REDIRECT_URIS)); - c.setRequestUris(getAsStringSet(o, REQUEST_URIS)); + c.setDefaultACRvalues(JsonUtils.getAsStringSet(o, DEFAULT_ACR_VALUES)); + c.setInitiateLoginUri(JsonUtils.getAsString(o, INITIATE_LOGIN_URI)); + c.setPostLogoutRedirectUris(JsonUtils.getAsStringSet(o, POST_LOGOUT_REDIRECT_URIS)); + c.setRequestUris(JsonUtils.getAsStringSet(o, REQUEST_URIS)); - c.setClaimsRedirectUris(getAsStringSet(o, CLAIMS_REDIRECT_URIS)); + c.setClaimsRedirectUris(JsonUtils.getAsStringSet(o, CLAIMS_REDIRECT_URIS)); - c.setCodeChallengeMethod(getAsPkceAlgorithm(o, CODE_CHALLENGE_METHOD)); + c.setCodeChallengeMethod(JsonUtils.getAsPkceAlgorithm(o, CODE_CHALLENGE_METHOD)); - c.setSoftwareId(getAsString(o, SOFTWARE_ID)); - c.setSoftwareVersion(getAsString(o, SOFTWARE_VERSION)); + c.setSoftwareId(JsonUtils.getAsString(o, SOFTWARE_ID)); + c.setSoftwareVersion(JsonUtils.getAsString(o, SOFTWARE_VERSION)); // note that this does not process or validate the software statement, that's handled in other components - String softwareStatement = getAsString(o, SOFTWARE_STATEMENT); + String softwareStatement = JsonUtils.getAsString(o, SOFTWARE_STATEMENT); if (!Strings.isNullOrEmpty(softwareStatement)) { try { JWT softwareStatementJwt = JWTParser.parse(softwareStatement); @@ -238,10 +232,10 @@ public class ClientDetailsEntityJsonProcessor { RegisteredClient rc = new RegisteredClient(c); // get any fields from the registration - rc.setRegistrationAccessToken(getAsString(o, REGISTRATION_ACCESS_TOKEN)); - rc.setRegistrationClientUri(getAsString(o, REGISTRATION_CLIENT_URI)); - rc.setClientIdIssuedAt(getAsDate(o, CLIENT_ID_ISSUED_AT)); - rc.setClientSecretExpiresAt(getAsDate(o, CLIENT_SECRET_EXPIRES_AT)); + rc.setRegistrationAccessToken(JsonUtils.getAsString(o, REGISTRATION_ACCESS_TOKEN)); + rc.setRegistrationClientUri(JsonUtils.getAsString(o, REGISTRATION_CLIENT_URI)); + rc.setClientIdIssuedAt(JsonUtils.getAsDate(o, CLIENT_ID_ISSUED_AT)); + rc.setClientSecretExpiresAt(JsonUtils.getAsDate(o, CLIENT_SECRET_EXPIRES_AT)); rc.setSource(o); @@ -294,15 +288,15 @@ public class ClientDetailsEntityJsonProcessor { // add in all other client properties // OAuth DynReg - o.add(REDIRECT_URIS, getAsArray(c.getRedirectUris())); + o.add(REDIRECT_URIS, JsonUtils.getAsArray(c.getRedirectUris())); o.addProperty(CLIENT_NAME, c.getClientName()); o.addProperty(CLIENT_URI, c.getClientUri()); - o.add(CONTACTS, getAsArray(c.getContacts())); + o.add(CONTACTS, JsonUtils.getAsArray(c.getContacts())); o.addProperty(TOS_URI, c.getTosUri()); o.addProperty(TOKEN_ENDPOINT_AUTH_METHOD, c.getTokenEndpointAuthMethod() != null ? c.getTokenEndpointAuthMethod().getValue() : null); o.addProperty(SCOPE, c.getScope() != null ? Joiner.on(SCOPE_SEPARATOR).join(c.getScope()) : null); - o.add(GRANT_TYPES, getAsArray(c.getGrantTypes())); - o.add(RESPONSE_TYPES, getAsArray(c.getResponseTypes())); + o.add(GRANT_TYPES, JsonUtils.getAsArray(c.getGrantTypes())); + o.add(RESPONSE_TYPES, JsonUtils.getAsArray(c.getResponseTypes())); o.addProperty(POLICY_URI, c.getPolicyUri()); o.addProperty(JWKS_URI, c.getJwksUri()); @@ -329,12 +323,12 @@ public class ClientDetailsEntityJsonProcessor { o.addProperty(TOKEN_ENDPOINT_AUTH_SIGNING_ALG, c.getTokenEndpointAuthSigningAlg() != null ? c.getTokenEndpointAuthSigningAlg().getName() : null); o.addProperty(DEFAULT_MAX_AGE, c.getDefaultMaxAge()); o.addProperty(REQUIRE_AUTH_TIME, c.getRequireAuthTime()); - o.add(DEFAULT_ACR_VALUES, getAsArray(c.getDefaultACRvalues())); + o.add(DEFAULT_ACR_VALUES, JsonUtils.getAsArray(c.getDefaultACRvalues())); o.addProperty(INITIATE_LOGIN_URI, c.getInitiateLoginUri()); - o.add(POST_LOGOUT_REDIRECT_URIS, getAsArray(c.getPostLogoutRedirectUris())); - o.add(REQUEST_URIS, getAsArray(c.getRequestUris())); + o.add(POST_LOGOUT_REDIRECT_URIS, JsonUtils.getAsArray(c.getPostLogoutRedirectUris())); + o.add(REQUEST_URIS, JsonUtils.getAsArray(c.getRequestUris())); - o.add(CLAIMS_REDIRECT_URIS, getAsArray(c.getClaimsRedirectUris())); + o.add(CLAIMS_REDIRECT_URIS, JsonUtils.getAsArray(c.getClaimsRedirectUris())); o.addProperty(CODE_CHALLENGE_METHOD, c.getCodeChallengeMethod() != null ? c.getCodeChallengeMethod().getName() : null); diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JWTBearerAssertionAuthenticationToken.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/assertion/JWTBearerAssertionAuthenticationToken.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JWTBearerAssertionAuthenticationToken.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/assertion/JWTBearerAssertionAuthenticationToken.java index bc4f9abcd..31df218a9 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JWTBearerAssertionAuthenticationToken.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/assertion/JWTBearerAssertionAuthenticationToken.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.assertion; +package cz.muni.ics.openid.connect.assertion; import java.text.ParseException; import java.util.Collection; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JWTBearerAuthenticationProvider.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/assertion/JWTBearerAuthenticationProvider.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JWTBearerAuthenticationProvider.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/assertion/JWTBearerAuthenticationProvider.java index 749a8eddd..4cf53dbad 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JWTBearerAuthenticationProvider.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/assertion/JWTBearerAuthenticationProvider.java @@ -18,19 +18,19 @@ /** * */ -package org.mitre.openid.connect.assertion; +package cz.muni.ics.openid.connect.assertion; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.jwt.signer.service.impl.ClientKeyCacheService; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; import java.text.ParseException; import java.util.Date; import java.util.HashSet; import java.util.Set; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.jwt.signer.service.impl.ClientKeyCacheService; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.AuthMethod; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JWTBearerClientAssertionTokenEndpointFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/assertion/JWTBearerClientAssertionTokenEndpointFilter.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JWTBearerClientAssertionTokenEndpointFilter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/assertion/JWTBearerClientAssertionTokenEndpointFilter.java index e1e5ca906..fa251833d 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JWTBearerClientAssertionTokenEndpointFilter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/assertion/JWTBearerClientAssertionTokenEndpointFilter.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.assertion; +package cz.muni.ics.openid.connect.assertion; import java.io.IOException; import java.text.ParseException; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/ConfigurationBeanLocaleResolver.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ConfigurationBeanLocaleResolver.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/config/ConfigurationBeanLocaleResolver.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ConfigurationBeanLocaleResolver.java index 5435f8d39..aa89bce52 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/ConfigurationBeanLocaleResolver.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ConfigurationBeanLocaleResolver.java @@ -16,7 +16,7 @@ /** * */ -package org.mitre.openid.connect.config; +package cz.muni.ics.openid.connect.config; import java.util.Locale; import java.util.TimeZone; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/ConfigurationPropertiesBean.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ConfigurationPropertiesBean.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/config/ConfigurationPropertiesBean.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ConfigurationPropertiesBean.java index 7e06e2a7a..b98b32820 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/ConfigurationPropertiesBean.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ConfigurationPropertiesBean.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.config; +package cz.muni.ics.openid.connect.config; import java.util.List; import java.util.Locale; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/JWKSetEditor.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/JWKSetEditor.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/config/JWKSetEditor.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/JWKSetEditor.java index 36d9246d2..43cce8638 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/JWKSetEditor.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/JWKSetEditor.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.config; +package cz.muni.ics.openid.connect.config; import java.beans.PropertyEditorSupport; import java.text.ParseException; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/JsonMessageSource.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/JsonMessageSource.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/config/JsonMessageSource.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/JsonMessageSource.java index 10746d3dd..03526b008 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/JsonMessageSource.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/JsonMessageSource.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.config; +package cz.muni.ics.openid.connect.config; import java.io.File; import java.io.FileNotFoundException; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/ServerConfiguration.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ServerConfiguration.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/config/ServerConfiguration.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ServerConfiguration.java index 54b173ae5..51097ba6f 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/ServerConfiguration.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ServerConfiguration.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.config; +package cz.muni.ics.openid.connect.config; import java.util.List; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/UIConfiguration.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/UIConfiguration.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/config/UIConfiguration.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/UIConfiguration.java index d4097cfbf..57f4d4384 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/config/UIConfiguration.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/UIConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.config; +package cz.muni.ics.openid.connect.config; import java.util.Set; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/exception/ValidationException.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/exception/ValidationException.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/exception/ValidationException.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/exception/ValidationException.java index 85efe2c87..17336639d 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/exception/ValidationException.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/exception/ValidationException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.exception; +package cz.muni.ics.openid.connect.exception; import org.springframework.http.HttpStatus; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/filter/AuthorizationRequestFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/filter/AuthorizationRequestFilter.java similarity index 81% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/filter/AuthorizationRequestFilter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/filter/AuthorizationRequestFilter.java index 63e239053..a8b9eba39 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/filter/AuthorizationRequestFilter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/filter/AuthorizationRequestFilter.java @@ -18,18 +18,13 @@ /** * */ -package org.mitre.openid.connect.filter; - -import static org.mitre.openid.connect.request.ConnectRequestParameters.ERROR; -import static org.mitre.openid.connect.request.ConnectRequestParameters.LOGIN_HINT; -import static org.mitre.openid.connect.request.ConnectRequestParameters.LOGIN_REQUIRED; -import static org.mitre.openid.connect.request.ConnectRequestParameters.MAX_AGE; -import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT; -import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_LOGIN; -import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_NONE; -import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_SEPARATOR; -import static org.mitre.openid.connect.request.ConnectRequestParameters.STATE; +package cz.muni.ics.openid.connect.filter; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.request.ConnectRequestParameters; +import cz.muni.ics.openid.connect.service.LoginHintExtracter; +import cz.muni.ics.openid.connect.service.impl.RemoveLoginHintsWithHTTP; +import cz.muni.ics.openid.connect.web.AuthenticationTimeStamper; import java.io.IOException; import java.net.URISyntaxException; import java.util.Date; @@ -46,11 +41,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.http.client.utils.URIBuilder; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.openid.connect.service.LoginHintExtracter; -import org.mitre.openid.connect.service.impl.RemoveLoginHintsWithHTTP; -import org.mitre.openid.connect.web.AuthenticationTimeStamper; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -126,19 +117,19 @@ public class AuthorizationRequestFilter extends GenericFilterBean { // save the login hint to the session // but first check to see if the login hint makes any sense - String loginHint = loginHintExtracter.extractHint((String) authRequest.getExtensions().get(LOGIN_HINT)); + String loginHint = loginHintExtracter.extractHint((String) authRequest.getExtensions().get(ConnectRequestParameters.LOGIN_HINT)); if (!Strings.isNullOrEmpty(loginHint)) { - session.setAttribute(LOGIN_HINT, loginHint); + session.setAttribute(ConnectRequestParameters.LOGIN_HINT, loginHint); } else { - session.removeAttribute(LOGIN_HINT); + session.removeAttribute(ConnectRequestParameters.LOGIN_HINT); } - if (authRequest.getExtensions().get(PROMPT) != null) { + if (authRequest.getExtensions().get(ConnectRequestParameters.PROMPT) != null) { // we have a "prompt" parameter - String prompt = (String)authRequest.getExtensions().get(PROMPT); - List<String> prompts = Splitter.on(PROMPT_SEPARATOR).splitToList(Strings.nullToEmpty(prompt)); + String prompt = (String)authRequest.getExtensions().get(ConnectRequestParameters.PROMPT); + List<String> prompts = Splitter.on(ConnectRequestParameters.PROMPT_SEPARATOR).splitToList(Strings.nullToEmpty(prompt)); - if (prompts.contains(PROMPT_NONE)) { + if (prompts.contains(ConnectRequestParameters.PROMPT_NONE)) { // see if the user's logged in Authentication auth = SecurityContextHolder.getContext().getAuthentication(); @@ -158,9 +149,9 @@ public class AuthorizationRequestFilter extends GenericFilterBean { try { URIBuilder uriBuilder = new URIBuilder(url); - uriBuilder.addParameter(ERROR, LOGIN_REQUIRED); + uriBuilder.addParameter(ConnectRequestParameters.ERROR, ConnectRequestParameters.LOGIN_REQUIRED); if (!Strings.isNullOrEmpty(authRequest.getState())) { - uriBuilder.addParameter(STATE, authRequest.getState()); // copy the state parameter if one was given + uriBuilder.addParameter(ConnectRequestParameters.STATE, authRequest.getState()); // copy the state parameter if one was given } response.sendRedirect(uriBuilder.toString()); @@ -176,7 +167,7 @@ public class AuthorizationRequestFilter extends GenericFilterBean { response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied"); return; } - } else if (prompts.contains(PROMPT_LOGIN)) { + } else if (prompts.contains(ConnectRequestParameters.PROMPT_LOGIN)) { // first see if the user's already been prompted in this session if (session.getAttribute(PROMPTED) == null) { @@ -207,12 +198,12 @@ public class AuthorizationRequestFilter extends GenericFilterBean { chain.doFilter(req, res); } - } else if (authRequest.getExtensions().get(MAX_AGE) != null || + } else if (authRequest.getExtensions().get(ConnectRequestParameters.MAX_AGE) != null || (client != null && client.getDefaultMaxAge() != null)) { // default to the client's stored value, check the string parameter Integer max = (client != null ? client.getDefaultMaxAge() : null); - String maxAge = (String) authRequest.getExtensions().get(MAX_AGE); + String maxAge = (String) authRequest.getExtensions().get(ConnectRequestParameters.MAX_AGE); if (maxAge != null) { max = Integer.parseInt(maxAge); } diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/filter/MultiUrlRequestMatcher.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/filter/MultiUrlRequestMatcher.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/filter/MultiUrlRequestMatcher.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/filter/MultiUrlRequestMatcher.java index 4f004dedf..d11d20d13 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/filter/MultiUrlRequestMatcher.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/filter/MultiUrlRequestMatcher.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.filter; +package cz.muni.ics.openid.connect.filter; import static org.springframework.web.bind.annotation.RequestMethod.OPTIONS; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/Address.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/Address.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/model/Address.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/Address.java index 40ff8820f..bf8a1f1b2 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/Address.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/Address.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.model; +package cz.muni.ics.openid.connect.model; import java.io.Serializable; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/ApprovedSite.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/ApprovedSite.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/model/ApprovedSite.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/ApprovedSite.java index d3f868ee4..2d710e03a 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/ApprovedSite.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/ApprovedSite.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.model; +package cz.muni.ics.openid.connect.model; import java.util.Date; import java.util.Set; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/BlacklistedSite.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/BlacklistedSite.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/model/BlacklistedSite.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/BlacklistedSite.java index 76531b5e4..defc96c76 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/BlacklistedSite.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/BlacklistedSite.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.model; +package cz.muni.ics.openid.connect.model; import javax.persistence.Basic; import javax.persistence.Column; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/DefaultAddress.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/DefaultAddress.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/model/DefaultAddress.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/DefaultAddress.java index 4a4cb5e8d..f63262f32 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/DefaultAddress.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/DefaultAddress.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.model; +package cz.muni.ics.openid.connect.model; import javax.persistence.Basic; import javax.persistence.Column; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/DefaultUserInfo.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/DefaultUserInfo.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/model/DefaultUserInfo.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/DefaultUserInfo.java index da152546d..2265d5b59 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/DefaultUserInfo.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/DefaultUserInfo.java @@ -15,8 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.model; +package cz.muni.ics.openid.connect.model; +import cz.muni.ics.openid.connect.model.convert.JsonObjectStringConverter; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -35,8 +36,6 @@ import javax.persistence.NamedQuery; import javax.persistence.OneToOne; import javax.persistence.Table; -import org.mitre.openid.connect.model.convert.JsonObjectStringConverter; - import com.google.gson.JsonObject; import com.google.gson.JsonParser; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/OIDCAuthenticationToken.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/OIDCAuthenticationToken.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/model/OIDCAuthenticationToken.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/OIDCAuthenticationToken.java index 56cea6959..7b5884761 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/OIDCAuthenticationToken.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/OIDCAuthenticationToken.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.model; +package cz.muni.ics.openid.connect.model; import java.io.IOException; import java.io.ObjectInputStream; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/PairwiseIdentifier.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/PairwiseIdentifier.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/model/PairwiseIdentifier.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/PairwiseIdentifier.java index 31bf8707b..a7f1a79b2 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/PairwiseIdentifier.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/PairwiseIdentifier.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.model; +package cz.muni.ics.openid.connect.model; import javax.persistence.Basic; import javax.persistence.Column; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/PendingOIDCAuthenticationToken.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/PendingOIDCAuthenticationToken.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/model/PendingOIDCAuthenticationToken.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/PendingOIDCAuthenticationToken.java index 74af8e9e1..96fe89a2f 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/PendingOIDCAuthenticationToken.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/PendingOIDCAuthenticationToken.java @@ -14,15 +14,15 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.model; +package cz.muni.ics.openid.connect.model; +import cz.muni.ics.openid.connect.config.ServerConfiguration; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.text.ParseException; import java.util.ArrayList; -import org.mitre.openid.connect.config.ServerConfiguration; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/UserInfo.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/UserInfo.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/model/UserInfo.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/UserInfo.java index 01d1df40b..c456e975e 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/UserInfo.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/UserInfo.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.model; +package cz.muni.ics.openid.connect.model; import java.io.Serializable; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/WhitelistedSite.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/WhitelistedSite.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/model/WhitelistedSite.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/WhitelistedSite.java index 6d6834e16..3d191939c 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/WhitelistedSite.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/WhitelistedSite.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.model; +package cz.muni.ics.openid.connect.model; import java.util.Set; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/convert/JsonObjectStringConverter.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/convert/JsonObjectStringConverter.java similarity index 94% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/model/convert/JsonObjectStringConverter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/convert/JsonObjectStringConverter.java index b2a0d60cd..ff485bbe4 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/model/convert/JsonObjectStringConverter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/model/convert/JsonObjectStringConverter.java @@ -14,12 +14,11 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.model.convert; +package cz.muni.ics.openid.connect.model.convert; import javax.persistence.AttributeConverter; import javax.persistence.Converter; -import com.google.common.base.Strings; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.springframework.util.StringUtils; diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/models/Acr.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/models/Acr.java new file mode 100644 index 000000000..9ec309e93 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/models/Acr.java @@ -0,0 +1,137 @@ +package cz.muni.ics.openid.connect.models; + +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; + +import static cz.muni.ics.openid.connect.models.Acr.PARAM_EXPIRES_AT; +import static cz.muni.ics.openid.connect.models.Acr.PARAM_SUB; + +/** + * Model of ACR. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@Entity +@Table(name = "acrs") +@NamedQueries({ + @NamedQuery(name = Acr.GET_ACTIVE, query = "SELECT acr FROM Acr acr WHERE " + + "acr.sub = :" + PARAM_SUB + + " AND acr.clientId = :" + Acr.PARAM_CLIENT_ID + + " AND acr.state = :" + Acr.PARAM_STATE + + " AND acr.expiresAt > :" + PARAM_EXPIRES_AT), + @NamedQuery(name = Acr.GET_BY_ID, + query = "SELECT acr FROM Acr acr " + + "WHERE acr.id = :" + Acr.PARAM_ID + + " AND acr.expiresAt > :" + PARAM_EXPIRES_AT), + @NamedQuery(name = Acr.DELETE_EXPIRED, + query = "DELETE FROM Acr acr WHERE acr.expiresAt <= :" + Acr.PARAM_EXPIRES_AT) +}) +public class Acr { + + public static final String GET_ACTIVE = "Acr.getActive"; + public static final String GET_BY_ID = "Acr.getById"; + public static final String DELETE_EXPIRED = "Acr.deleteExpired"; + + public static final String PARAM_ID = "id"; + public static final String PARAM_SUB = "sub"; + public static final String PARAM_CLIENT_ID = "client_id"; + public static final String PARAM_STATE = "state"; + public static final String PARAM_EXPIRES_AT = "expiration"; + + private Long id; + private String sub; + private String clientId; + private String state; + private String shibAuthnContextClass; + private long expiresAt; + + public Acr() { } + + public Acr(String sub, String clientId, String state, String shibAuthnContextClass, long expiresAt) { + this.sub = sub; + this.clientId = clientId; + this.state = state; + this.shibAuthnContextClass = shibAuthnContextClass; + this.expiresAt = expiresAt; + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + @Basic + @Column(name = "sub") + public String getSub() { + return sub; + } + + public void setSub(String sub) { + this.sub = sub; + } + + @Basic + @Column(name = "client_id") + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + @Basic + @Column(name = "state") + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + @Basic + @Column(name = "shib_authn_context_class") + public String getShibAuthnContextClass() { + return shibAuthnContextClass; + } + + public void setShibAuthnContextClass(String shibAuthnContextClass) { + this.shibAuthnContextClass = shibAuthnContextClass; + } + + @Basic + @Column(name = "expiration") + public long getExpiresAt() { + return expiresAt; + } + + public void setExpiresAt(long expiresAt) { + this.expiresAt = expiresAt; + } + + @Override + public String toString() { + return "Acr{" + + "id=" + id + + ", sub='" + sub + '\'' + + ", clientId='" + clientId + '\'' + + ", state='" + state + '\'' + + ", shibAuthnContextClass='" + shibAuthnContextClass + '\'' + + ", expiration=" + expiresAt + + '}'; + } +} diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/models/DeviceCodeAcr.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/models/DeviceCodeAcr.java new file mode 100644 index 000000000..2c528c3f7 --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/models/DeviceCodeAcr.java @@ -0,0 +1,122 @@ +package cz.muni.ics.openid.connect.models; + +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; + +/** + * Model of ACR for device_code flow. + * + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@Entity +@Table(name = "device_code_acrs") +@NamedQueries({ + @NamedQuery(name = DeviceCodeAcr.GET_ACTIVE_BY_DEVICE_CODE, + query = "SELECT acr FROM DeviceCodeAcr acr WHERE " + + "acr.deviceCode = :" + DeviceCodeAcr.PARAM_DEVICE_CODE + + " AND acr.expiresAt > :" + DeviceCodeAcr.PARAM_EXPIRES_AT), + @NamedQuery(name = DeviceCodeAcr.GET_BY_ID, + query = "SELECT acr FROM DeviceCodeAcr acr " + + "WHERE acr.id = :" + DeviceCodeAcr.PARAM_ID + + " AND acr.expiresAt > :" + DeviceCodeAcr.PARAM_EXPIRES_AT), + @NamedQuery(name = DeviceCodeAcr.GET_BY_USER_CODE, + query = "SELECT acr FROM DeviceCodeAcr acr " + + "WHERE acr.userCode = :" + DeviceCodeAcr.PARAM_USER_CODE), + @NamedQuery(name = DeviceCodeAcr.DELETE_EXPIRED, + query = "DELETE FROM DeviceCodeAcr acr WHERE acr.expiresAt <= :" + DeviceCodeAcr.PARAM_EXPIRES_AT) +}) +public class DeviceCodeAcr { + + public static final String GET_ACTIVE_BY_DEVICE_CODE = "DeviceCodeAcr.getActive"; + public static final String GET_BY_ID = "DeviceCodeAcr.getById"; + public static final String DELETE_EXPIRED = "DeviceCodeAcr.deleteExpired"; + public static final String GET_BY_USER_CODE = "DeviceCodeAcr.getByUserCode"; + + public static final String PARAM_ID = "id"; + public static final String PARAM_USER_CODE = "user_code"; + public static final String PARAM_DEVICE_CODE = "device_code"; + public static final String PARAM_EXPIRES_AT = "expiration"; + + private Long id; + private String userCode; + private String deviceCode; + private String shibAuthnContextClass; + private long expiresAt; + + public DeviceCodeAcr() { } + + public DeviceCodeAcr(String deviceCode, String userCode) { + this.deviceCode = deviceCode; + this.userCode = userCode; + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + @Basic + @Column(name = "device_code") + public String getDeviceCode() { + return deviceCode; + } + + public void setDeviceCode(String deviceCode) { + this.deviceCode = deviceCode; + } + + @Basic + @Column(name = "user_code") + public String getUserCode() { + return userCode; + } + + public void setUserCode(String userCode) { + this.userCode = userCode; + } + + @Basic + @Column(name = "shib_authn_context_class") + public String getShibAuthnContextClass() { + return shibAuthnContextClass; + } + + public void setShibAuthnContextClass(String shibAuthnContextClass) { + this.shibAuthnContextClass = shibAuthnContextClass; + } + + @Basic + @Column(name = "expiration") + public long getExpiresAt() { + return expiresAt; + } + + public void setExpiresAt(long expiresAt) { + this.expiresAt = expiresAt; + } + + @Override + public String toString() { + return "Acr{" + + "id=" + id + + ", deviceCode='" + deviceCode + '\'' + + ", userCode='" + userCode + '\'' + + ", shibAuthnContextClass='" + shibAuthnContextClass + '\'' + + ", expiration=" + expiresAt + + '}'; + } + +} diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/AddressRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/AddressRepository.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/AddressRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/AddressRepository.java index 16c6f48cb..77b6ed6f3 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/AddressRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/AddressRepository.java @@ -15,9 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.repository; +package cz.muni.ics.openid.connect.repository; -import org.mitre.openid.connect.model.Address; +import cz.muni.ics.openid.connect.model.Address; /** * Address repository interface diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/ApprovedSiteRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/ApprovedSiteRepository.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/ApprovedSiteRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/ApprovedSiteRepository.java index 65b20d54b..b64efc570 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/ApprovedSiteRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/ApprovedSiteRepository.java @@ -15,11 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.repository; +package cz.muni.ics.openid.connect.repository; import java.util.Collection; -import org.mitre.openid.connect.model.ApprovedSite; +import cz.muni.ics.openid.connect.model.ApprovedSite; /** * ApprovedSite repository interface diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/BlacklistedSiteRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/BlacklistedSiteRepository.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/BlacklistedSiteRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/BlacklistedSiteRepository.java index ec0b332c0..7f94d2887 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/BlacklistedSiteRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/BlacklistedSiteRepository.java @@ -18,11 +18,11 @@ /** * */ -package org.mitre.openid.connect.repository; +package cz.muni.ics.openid.connect.repository; import java.util.Collection; -import org.mitre.openid.connect.model.BlacklistedSite; +import cz.muni.ics.openid.connect.model.BlacklistedSite; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/PairwiseIdentifierRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/PairwiseIdentifierRepository.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/PairwiseIdentifierRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/PairwiseIdentifierRepository.java index 930164829..9a7ea6b81 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/PairwiseIdentifierRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/PairwiseIdentifierRepository.java @@ -18,9 +18,9 @@ /** * */ -package org.mitre.openid.connect.repository; +package cz.muni.ics.openid.connect.repository; -import org.mitre.openid.connect.model.PairwiseIdentifier; +import cz.muni.ics.openid.connect.model.PairwiseIdentifier; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/UserInfoRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/UserInfoRepository.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/UserInfoRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/UserInfoRepository.java index 8dbc4714d..67167d9fa 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/UserInfoRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/UserInfoRepository.java @@ -15,9 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.repository; +package cz.muni.ics.openid.connect.repository; -import org.mitre.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.model.UserInfo; /** * UserInfo repository interface diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/WhitelistedSiteRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/WhitelistedSiteRepository.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/WhitelistedSiteRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/WhitelistedSiteRepository.java index e7aee372e..616584acd 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/WhitelistedSiteRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/WhitelistedSiteRepository.java @@ -15,11 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.repository; +package cz.muni.ics.openid.connect.repository; import java.util.Collection; -import org.mitre.openid.connect.model.WhitelistedSite; +import cz.muni.ics.openid.connect.model.WhitelistedSite; /** * WhitelistedSite repository interface diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaAddressRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaAddressRepository.java similarity index 89% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaAddressRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaAddressRepository.java index c2556d62f..fe5fbed49 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaAddressRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaAddressRepository.java @@ -15,13 +15,13 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.repository.impl; +package cz.muni.ics.openid.connect.repository.impl; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; -import org.mitre.openid.connect.model.Address; -import org.mitre.openid.connect.repository.AddressRepository; +import cz.muni.ics.openid.connect.model.Address; +import cz.muni.ics.openid.connect.repository.AddressRepository; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaApprovedSiteRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaApprovedSiteRepository.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaApprovedSiteRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaApprovedSiteRepository.java index fd8c34108..a9a02b56d 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaApprovedSiteRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaApprovedSiteRepository.java @@ -15,18 +15,17 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.repository.impl; - -import static org.mitre.util.jpa.JpaUtil.saveOrUpdate; +package cz.muni.ics.openid.connect.repository.impl; +import cz.muni.ics.util.jpa.JpaUtil; import java.util.Collection; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; -import org.mitre.openid.connect.model.ApprovedSite; -import org.mitre.openid.connect.repository.ApprovedSiteRepository; +import cz.muni.ics.openid.connect.model.ApprovedSite; +import cz.muni.ics.openid.connect.repository.ApprovedSiteRepository; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -70,7 +69,7 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository { @Override @Transactional(value="defaultTransactionManager") public ApprovedSite save(ApprovedSite approvedSite) { - return saveOrUpdate(manager, approvedSite); + return JpaUtil.saveOrUpdate(manager, approvedSite); } @Override diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaBlacklistedSiteRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaBlacklistedSiteRepository.java similarity index 72% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaBlacklistedSiteRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaBlacklistedSiteRepository.java index 643bf9b8b..c2c38ce9f 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaBlacklistedSiteRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaBlacklistedSiteRepository.java @@ -18,18 +18,17 @@ /** * */ -package org.mitre.openid.connect.repository.impl; - -import static org.mitre.util.jpa.JpaUtil.saveOrUpdate; +package cz.muni.ics.openid.connect.repository.impl; +import cz.muni.ics.util.jpa.JpaUtil; import java.util.Collection; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; -import org.mitre.openid.connect.model.BlacklistedSite; -import org.mitre.openid.connect.repository.BlacklistedSiteRepository; +import cz.muni.ics.openid.connect.model.BlacklistedSite; +import cz.muni.ics.openid.connect.repository.BlacklistedSiteRepository; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -44,7 +43,7 @@ public class JpaBlacklistedSiteRepository implements BlacklistedSiteRepository { private EntityManager manager; /* (non-Javadoc) - * @see org.mitre.openid.connect.repository.BlacklistedSiteRepository#getAll() + * @see cz.muni.ics.openid.connect.repository.BlacklistedSiteRepository#getAll() */ @Override @Transactional(value="defaultTransactionManager") @@ -54,7 +53,7 @@ public class JpaBlacklistedSiteRepository implements BlacklistedSiteRepository { } /* (non-Javadoc) - * @see org.mitre.openid.connect.repository.BlacklistedSiteRepository#getById(java.lang.Long) + * @see cz.muni.ics.openid.connect.repository.BlacklistedSiteRepository#getById(java.lang.Long) */ @Override @Transactional(value="defaultTransactionManager") @@ -63,7 +62,7 @@ public class JpaBlacklistedSiteRepository implements BlacklistedSiteRepository { } /* (non-Javadoc) - * @see org.mitre.openid.connect.repository.BlacklistedSiteRepository#remove(org.mitre.openid.connect.model.BlacklistedSite) + * @see cz.muni.ics.openid.connect.repository.BlacklistedSiteRepository#remove(cz.muni.ics.openid.connect.model.BlacklistedSite) */ @Override @Transactional(value="defaultTransactionManager") @@ -79,23 +78,23 @@ public class JpaBlacklistedSiteRepository implements BlacklistedSiteRepository { } /* (non-Javadoc) - * @see org.mitre.openid.connect.repository.BlacklistedSiteRepository#save(org.mitre.openid.connect.model.BlacklistedSite) + * @see cz.muni.ics.openid.connect.repository.BlacklistedSiteRepository#save(cz.muni.ics.openid.connect.model.BlacklistedSite) */ @Override @Transactional(value="defaultTransactionManager") public BlacklistedSite save(BlacklistedSite blacklistedSite) { - return saveOrUpdate(manager, blacklistedSite); + return JpaUtil.saveOrUpdate(manager, blacklistedSite); } /* (non-Javadoc) - * @see org.mitre.openid.connect.repository.BlacklistedSiteRepository#update(org.mitre.openid.connect.model.BlacklistedSite, org.mitre.openid.connect.model.BlacklistedSite) + * @see cz.muni.ics.openid.connect.repository.BlacklistedSiteRepository#update(cz.muni.ics.openid.connect.model.BlacklistedSite, cz.muni.ics.openid.connect.model.BlacklistedSite) */ @Override @Transactional(value="defaultTransactionManager") public BlacklistedSite update(BlacklistedSite oldBlacklistedSite, BlacklistedSite blacklistedSite) { blacklistedSite.setId(oldBlacklistedSite.getId()); - return saveOrUpdate(manager, blacklistedSite); + return JpaUtil.saveOrUpdate(manager, blacklistedSite); } diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaPairwiseIdentifierRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaPairwiseIdentifierRepository.java similarity index 74% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaPairwiseIdentifierRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaPairwiseIdentifierRepository.java index 4289d51a7..2be01e029 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaPairwiseIdentifierRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaPairwiseIdentifierRepository.java @@ -18,17 +18,15 @@ /** * */ -package org.mitre.openid.connect.repository.impl; - -import static org.mitre.util.jpa.JpaUtil.getSingleResult; -import static org.mitre.util.jpa.JpaUtil.saveOrUpdate; +package cz.muni.ics.openid.connect.repository.impl; +import cz.muni.ics.util.jpa.JpaUtil; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; -import org.mitre.openid.connect.model.PairwiseIdentifier; -import org.mitre.openid.connect.repository.PairwiseIdentifierRepository; +import cz.muni.ics.openid.connect.model.PairwiseIdentifier; +import cz.muni.ics.openid.connect.repository.PairwiseIdentifierRepository; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -43,7 +41,7 @@ public class JpaPairwiseIdentifierRepository implements PairwiseIdentifierReposi private EntityManager manager; /* (non-Javadoc) - * @see org.mitre.openid.connect.repository.PairwiseIdentifierRepository#getBySectorIdentifier(java.lang.String, java.lang.String) + * @see cz.muni.ics.openid.connect.repository.PairwiseIdentifierRepository#getBySectorIdentifier(java.lang.String, java.lang.String) */ @Override public PairwiseIdentifier getBySectorIdentifier(String sub, String sectorIdentifierUri) { @@ -51,16 +49,16 @@ public class JpaPairwiseIdentifierRepository implements PairwiseIdentifierReposi query.setParameter(PairwiseIdentifier.PARAM_SUB, sub); query.setParameter(PairwiseIdentifier.PARAM_SECTOR_IDENTIFIER, sectorIdentifierUri); - return getSingleResult(query.getResultList()); + return JpaUtil.getSingleResult(query.getResultList()); } /* (non-Javadoc) - * @see org.mitre.openid.connect.repository.PairwiseIdentifierRepository#save(org.mitre.openid.connect.model.PairwiseIdentifier) + * @see cz.muni.ics.openid.connect.repository.PairwiseIdentifierRepository#save(cz.muni.ics.openid.connect.model.PairwiseIdentifier) */ @Override @Transactional(value="defaultTransactionManager") public void save(PairwiseIdentifier pairwise) { - saveOrUpdate(manager, pairwise); + JpaUtil.saveOrUpdate(manager, pairwise); } } diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaUserInfoRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaUserInfoRepository.java similarity index 83% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaUserInfoRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaUserInfoRepository.java index 7627246da..8ab345473 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaUserInfoRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaUserInfoRepository.java @@ -15,17 +15,16 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.repository.impl; - -import static org.mitre.util.jpa.JpaUtil.getSingleResult; +package cz.muni.ics.openid.connect.repository.impl; +import cz.muni.ics.util.jpa.JpaUtil; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; -import org.mitre.openid.connect.model.DefaultUserInfo; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.repository.UserInfoRepository; +import cz.muni.ics.openid.connect.model.DefaultUserInfo; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.repository.UserInfoRepository; import org.springframework.stereotype.Repository; /** @@ -48,7 +47,7 @@ public class JpaUserInfoRepository implements UserInfoRepository { TypedQuery<DefaultUserInfo> query = manager.createNamedQuery(DefaultUserInfo.QUERY_BY_USERNAME, DefaultUserInfo.class); query.setParameter(DefaultUserInfo.PARAM_USERNAME, username); - return getSingleResult(query.getResultList()); + return JpaUtil.getSingleResult(query.getResultList()); } @@ -60,7 +59,7 @@ public class JpaUserInfoRepository implements UserInfoRepository { TypedQuery<DefaultUserInfo> query = manager.createNamedQuery(DefaultUserInfo.QUERY_BY_EMAIL, DefaultUserInfo.class); query.setParameter(DefaultUserInfo.PARAM_EMAIL, email); - return getSingleResult(query.getResultList()); + return JpaUtil.getSingleResult(query.getResultList()); } } diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaWhitelistedSiteRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaWhitelistedSiteRepository.java similarity index 89% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaWhitelistedSiteRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaWhitelistedSiteRepository.java index 9f8e57c09..044f65ae5 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/repository/impl/JpaWhitelistedSiteRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/repository/impl/JpaWhitelistedSiteRepository.java @@ -15,19 +15,17 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.repository.impl; - -import static org.mitre.util.jpa.JpaUtil.saveOrUpdate; +package cz.muni.ics.openid.connect.repository.impl; +import cz.muni.ics.util.jpa.JpaUtil; import java.util.Collection; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; -import org.mitre.openid.connect.model.WhitelistedSite; -import org.mitre.openid.connect.repository.WhitelistedSiteRepository; -import org.mitre.util.jpa.JpaUtil; +import cz.muni.ics.openid.connect.model.WhitelistedSite; +import cz.muni.ics.openid.connect.repository.WhitelistedSiteRepository; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -71,7 +69,7 @@ public class JpaWhitelistedSiteRepository implements WhitelistedSiteRepository { @Override @Transactional(value="defaultTransactionManager") public WhitelistedSite save(WhitelistedSite whiteListedSite) { - return saveOrUpdate(manager, whiteListedSite); + return JpaUtil.saveOrUpdate(manager, whiteListedSite); } @Override @@ -80,7 +78,7 @@ public class JpaWhitelistedSiteRepository implements WhitelistedSiteRepository { // sanity check whitelistedSite.setId(oldWhitelistedSite.getId()); - return saveOrUpdate(manager, whitelistedSite); + return JpaUtil.saveOrUpdate(manager, whitelistedSite); } @Override diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/request/ConnectOAuth2RequestFactory.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/request/ConnectOAuth2RequestFactory.java similarity index 71% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/request/ConnectOAuth2RequestFactory.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/request/ConnectOAuth2RequestFactory.java index d957f31a4..561bbbe1f 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/request/ConnectOAuth2RequestFactory.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/request/ConnectOAuth2RequestFactory.java @@ -15,37 +15,21 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.request; +package cz.muni.ics.openid.connect.request; -import static org.mitre.openid.connect.request.ConnectRequestParameters.AUD; -import static org.mitre.openid.connect.request.ConnectRequestParameters.CLAIMS; -import static org.mitre.openid.connect.request.ConnectRequestParameters.CLIENT_ID; -import static org.mitre.openid.connect.request.ConnectRequestParameters.CODE_CHALLENGE; -import static org.mitre.openid.connect.request.ConnectRequestParameters.CODE_CHALLENGE_METHOD; -import static org.mitre.openid.connect.request.ConnectRequestParameters.DISPLAY; -import static org.mitre.openid.connect.request.ConnectRequestParameters.LOGIN_HINT; -import static org.mitre.openid.connect.request.ConnectRequestParameters.MAX_AGE; -import static org.mitre.openid.connect.request.ConnectRequestParameters.NONCE; -import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT; -import static org.mitre.openid.connect.request.ConnectRequestParameters.REDIRECT_URI; -import static org.mitre.openid.connect.request.ConnectRequestParameters.REQUEST; -import static org.mitre.openid.connect.request.ConnectRequestParameters.RESPONSE_TYPE; -import static org.mitre.openid.connect.request.ConnectRequestParameters.SCOPE; -import static org.mitre.openid.connect.request.ConnectRequestParameters.STATE; - +import cz.muni.ics.jwt.encryption.service.JWTEncryptionAndDecryptionService; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.jwt.signer.service.impl.ClientKeyCacheService; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; import java.io.Serializable; import java.text.ParseException; import java.util.Collections; import java.util.Map; import java.util.Set; -import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.jwt.signer.service.impl.ClientKeyCacheService; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.PKCEAlgorithm; -import org.mitre.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.PKCEAlgorithm; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -112,46 +96,46 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { //Add extension parameters to the 'extensions' map - if (inputParams.containsKey(PROMPT)) { - request.getExtensions().put(PROMPT, inputParams.get(PROMPT)); + if (inputParams.containsKey(ConnectRequestParameters.PROMPT)) { + request.getExtensions().put(ConnectRequestParameters.PROMPT, inputParams.get(ConnectRequestParameters.PROMPT)); } - if (inputParams.containsKey(NONCE)) { - request.getExtensions().put(NONCE, inputParams.get(NONCE)); + if (inputParams.containsKey(ConnectRequestParameters.NONCE)) { + request.getExtensions().put(ConnectRequestParameters.NONCE, inputParams.get(ConnectRequestParameters.NONCE)); } - if (inputParams.containsKey(CLAIMS)) { - JsonObject claimsRequest = parseClaimRequest(inputParams.get(CLAIMS)); + if (inputParams.containsKey(ConnectRequestParameters.CLAIMS)) { + JsonObject claimsRequest = parseClaimRequest(inputParams.get(ConnectRequestParameters.CLAIMS)); if (claimsRequest != null) { - request.getExtensions().put(CLAIMS, claimsRequest.toString()); + request.getExtensions().put(ConnectRequestParameters.CLAIMS, claimsRequest.toString()); } } - if (inputParams.containsKey(MAX_AGE)) { - request.getExtensions().put(MAX_AGE, inputParams.get(MAX_AGE)); + if (inputParams.containsKey(ConnectRequestParameters.MAX_AGE)) { + request.getExtensions().put(ConnectRequestParameters.MAX_AGE, inputParams.get(ConnectRequestParameters.MAX_AGE)); } - if (inputParams.containsKey(LOGIN_HINT)) { - request.getExtensions().put(LOGIN_HINT, inputParams.get(LOGIN_HINT)); + if (inputParams.containsKey(ConnectRequestParameters.LOGIN_HINT)) { + request.getExtensions().put(ConnectRequestParameters.LOGIN_HINT, inputParams.get(ConnectRequestParameters.LOGIN_HINT)); } - if (inputParams.containsKey(AUD)) { - request.getExtensions().put(AUD, inputParams.get(AUD)); + if (inputParams.containsKey(ConnectRequestParameters.AUD)) { + request.getExtensions().put(ConnectRequestParameters.AUD, inputParams.get(ConnectRequestParameters.AUD)); } - if (inputParams.containsKey(CODE_CHALLENGE)) { - request.getExtensions().put(CODE_CHALLENGE, inputParams.get(CODE_CHALLENGE)); - if (inputParams.containsKey(CODE_CHALLENGE_METHOD)) { - request.getExtensions().put(CODE_CHALLENGE_METHOD, inputParams.get(CODE_CHALLENGE_METHOD)); + if (inputParams.containsKey(ConnectRequestParameters.CODE_CHALLENGE)) { + request.getExtensions().put(ConnectRequestParameters.CODE_CHALLENGE, inputParams.get(ConnectRequestParameters.CODE_CHALLENGE)); + if (inputParams.containsKey(ConnectRequestParameters.CODE_CHALLENGE_METHOD)) { + request.getExtensions().put(ConnectRequestParameters.CODE_CHALLENGE_METHOD, inputParams.get(ConnectRequestParameters.CODE_CHALLENGE_METHOD)); } else { // if the client doesn't specify a code challenge transformation method, it's "plain" - request.getExtensions().put(CODE_CHALLENGE_METHOD, PKCEAlgorithm.plain.getName()); + request.getExtensions().put(ConnectRequestParameters.CODE_CHALLENGE_METHOD, PKCEAlgorithm.plain.getName()); } } - if (inputParams.containsKey(REQUEST)) { - request.getExtensions().put(REQUEST, inputParams.get(REQUEST)); - processRequestObject(inputParams.get(REQUEST), request); + if (inputParams.containsKey(ConnectRequestParameters.REQUEST)) { + request.getExtensions().put(ConnectRequestParameters.REQUEST, inputParams.get(ConnectRequestParameters.REQUEST)); + processRequestObject(inputParams.get(ConnectRequestParameters.REQUEST), request); } if (request.getClientId() != null) { @@ -163,8 +147,8 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { request.setScope(clientScopes); } - if (request.getExtensions().get(MAX_AGE) == null && client.getDefaultMaxAge() != null) { - request.getExtensions().put(MAX_AGE, client.getDefaultMaxAge().toString()); + if (request.getExtensions().get(ConnectRequestParameters.MAX_AGE) == null && client.getDefaultMaxAge() != null) { + request.getExtensions().put(ConnectRequestParameters.MAX_AGE, client.getDefaultMaxAge().toString()); } } catch (OAuth2Exception e) { logger.error("Caught OAuth2 exception trying to test client scopes and max age:", e); @@ -192,7 +176,7 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { // need to check clientId first so that we can load the client to check other fields if (request.getClientId() == null) { - request.setClientId(signedJwt.getJWTClaimsSet().getStringClaim(CLIENT_ID)); + request.setClientId(signedJwt.getJWTClaimsSet().getStringClaim(ConnectRequestParameters.CLIENT_ID)); } ClientDetailsEntity client = clientDetailsService.loadClientByClientId(request.getClientId()); @@ -224,7 +208,7 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { // need to check clientId first so that we can load the client to check other fields if (request.getClientId() == null) { - request.setClientId(plainJwt.getJWTClaimsSet().getStringClaim(CLIENT_ID)); + request.setClientId(plainJwt.getJWTClaimsSet().getStringClaim(ConnectRequestParameters.CLIENT_ID)); } ClientDetailsEntity client = clientDetailsService.loadClientByClientId(request.getClientId()); @@ -257,7 +241,7 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { // need to check clientId first so that we can load the client to check other fields if (request.getClientId() == null) { - request.setClientId(encryptedJWT.getJWTClaimsSet().getStringClaim(CLIENT_ID)); + request.setClientId(encryptedJWT.getJWTClaimsSet().getStringClaim(ConnectRequestParameters.CLIENT_ID)); } ClientDetailsEntity client = clientDetailsService.loadClientByClientId(request.getClientId()); @@ -278,7 +262,7 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { JWTClaimsSet claims = jwt.getJWTClaimsSet(); - Set<String> responseTypes = OAuth2Utils.parseParameterList(claims.getStringClaim(RESPONSE_TYPE)); + Set<String> responseTypes = OAuth2Utils.parseParameterList(claims.getStringClaim(ConnectRequestParameters.RESPONSE_TYPE)); if (!responseTypes.isEmpty()) { if (!responseTypes.equals(request.getResponseTypes())) { logger.info("Mismatch between request object and regular parameter for response_type, using request object"); @@ -286,7 +270,7 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { request.setResponseTypes(responseTypes); } - String redirectUri = claims.getStringClaim(REDIRECT_URI); + String redirectUri = claims.getStringClaim(ConnectRequestParameters.REDIRECT_URI); if (redirectUri != null) { if (!redirectUri.equals(request.getRedirectUri())) { logger.info("Mismatch between request object and regular parameter for redirect_uri, using request object"); @@ -294,7 +278,7 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { request.setRedirectUri(redirectUri); } - String state = claims.getStringClaim(STATE); + String state = claims.getStringClaim(ConnectRequestParameters.STATE); if(state != null) { if (!state.equals(request.getState())) { logger.info("Mismatch between request object and regular parameter for state, using request object"); @@ -302,31 +286,31 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { request.setState(state); } - String nonce = claims.getStringClaim(NONCE); + String nonce = claims.getStringClaim(ConnectRequestParameters.NONCE); if(nonce != null) { - if (!nonce.equals(request.getExtensions().get(NONCE))) { + if (!nonce.equals(request.getExtensions().get(ConnectRequestParameters.NONCE))) { logger.info("Mismatch between request object and regular parameter for nonce, using request object"); } - request.getExtensions().put(NONCE, nonce); + request.getExtensions().put(ConnectRequestParameters.NONCE, nonce); } - String display = claims.getStringClaim(DISPLAY); + String display = claims.getStringClaim(ConnectRequestParameters.DISPLAY); if (display != null) { - if (!display.equals(request.getExtensions().get(DISPLAY))) { + if (!display.equals(request.getExtensions().get(ConnectRequestParameters.DISPLAY))) { logger.info("Mismatch between request object and regular parameter for display, using request object"); } - request.getExtensions().put(DISPLAY, display); + request.getExtensions().put(ConnectRequestParameters.DISPLAY, display); } - String prompt = claims.getStringClaim(PROMPT); + String prompt = claims.getStringClaim(ConnectRequestParameters.PROMPT); if (prompt != null) { - if (!prompt.equals(request.getExtensions().get(PROMPT))) { + if (!prompt.equals(request.getExtensions().get(ConnectRequestParameters.PROMPT))) { logger.info("Mismatch between request object and regular parameter for prompt, using request object"); } - request.getExtensions().put(PROMPT, prompt); + request.getExtensions().put(ConnectRequestParameters.PROMPT, prompt); } - Set<String> scope = OAuth2Utils.parseParameterList(claims.getStringClaim(SCOPE)); + Set<String> scope = OAuth2Utils.parseParameterList(claims.getStringClaim(ConnectRequestParameters.SCOPE)); if (!scope.isEmpty()) { if (!scope.equals(request.getScope())) { logger.info("Mismatch between request object and regular parameter for scope, using request object"); @@ -334,22 +318,22 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { request.setScope(scope); } - JsonObject claimRequest = parseClaimRequest(claims.getStringClaim(CLAIMS)); + JsonObject claimRequest = parseClaimRequest(claims.getStringClaim(ConnectRequestParameters.CLAIMS)); if (claimRequest != null) { - Serializable claimExtension = request.getExtensions().get(CLAIMS); + Serializable claimExtension = request.getExtensions().get(ConnectRequestParameters.CLAIMS); if (claimExtension == null || !claimRequest.equals(parseClaimRequest(claimExtension.toString()))) { logger.info("Mismatch between request object and regular parameter for claims, using request object"); } // we save the string because the object might not be a Java Serializable, and we can parse it easily enough anyway - request.getExtensions().put(CLAIMS, claimRequest.toString()); + request.getExtensions().put(ConnectRequestParameters.CLAIMS, claimRequest.toString()); } - String loginHint = claims.getStringClaim(LOGIN_HINT); + String loginHint = claims.getStringClaim(ConnectRequestParameters.LOGIN_HINT); if (loginHint != null) { - if (!loginHint.equals(request.getExtensions().get(LOGIN_HINT))) { + if (!loginHint.equals(request.getExtensions().get(ConnectRequestParameters.LOGIN_HINT))) { logger.info("Mistmatch between request object and regular parameter for login_hint, using requst object"); } - request.getExtensions().put(LOGIN_HINT, loginHint); + request.getExtensions().put(ConnectRequestParameters.LOGIN_HINT, loginHint); } } catch (ParseException e) { diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/request/ConnectRequestParameters.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/request/ConnectRequestParameters.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/request/ConnectRequestParameters.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/request/ConnectRequestParameters.java index cebcdd169..0a17505b6 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/request/ConnectRequestParameters.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/request/ConnectRequestParameters.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.request; +package cz.muni.ics.openid.connect.request; public interface ConnectRequestParameters { diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/ApprovedSiteService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/ApprovedSiteService.java similarity index 94% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/ApprovedSiteService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/ApprovedSiteService.java index da67a940b..12bf07d6f 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/ApprovedSiteService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/ApprovedSiteService.java @@ -15,15 +15,15 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service; +package cz.muni.ics.openid.connect.service; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.openid.connect.model.ApprovedSite; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Set; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.openid.connect.model.ApprovedSite; import org.springframework.security.oauth2.provider.ClientDetails; /** diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/BlacklistedSiteService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/BlacklistedSiteService.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/BlacklistedSiteService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/BlacklistedSiteService.java index efe9e1846..50204a710 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/BlacklistedSiteService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/BlacklistedSiteService.java @@ -18,11 +18,11 @@ /** * */ -package org.mitre.openid.connect.service; +package cz.muni.ics.openid.connect.service; import java.util.Collection; -import org.mitre.openid.connect.model.BlacklistedSite; +import cz.muni.ics.openid.connect.model.BlacklistedSite; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/LoginHintExtracter.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/LoginHintExtracter.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/LoginHintExtracter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/LoginHintExtracter.java index d5d8cd2ac..b9e7a4fae 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/LoginHintExtracter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/LoginHintExtracter.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service; +package cz.muni.ics.openid.connect.service; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/OIDCTokenService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/OIDCTokenService.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/OIDCTokenService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/OIDCTokenService.java index 55d1c0d13..aa1766245 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/OIDCTokenService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/OIDCTokenService.java @@ -15,12 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service; +package cz.muni.ics.openid.connect.service; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; import java.util.Date; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; import org.springframework.security.oauth2.provider.OAuth2Request; import com.nimbusds.jwt.JWT; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/PairwiseIdentiferService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/PairwiseIdentiferService.java similarity index 89% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/PairwiseIdentiferService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/PairwiseIdentiferService.java index 0e4747f11..563e161fc 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/PairwiseIdentiferService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/PairwiseIdentiferService.java @@ -18,10 +18,10 @@ /** * */ -package org.mitre.openid.connect.service; +package cz.muni.ics.openid.connect.service; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.openid.connect.model.UserInfo; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.openid.connect.model.UserInfo; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/ScopeClaimTranslationService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/ScopeClaimTranslationService.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/ScopeClaimTranslationService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/ScopeClaimTranslationService.java index 43f00f489..ffc7dd9c2 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/ScopeClaimTranslationService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/ScopeClaimTranslationService.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.service; +package cz.muni.ics.openid.connect.service; import java.util.Set; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/UserInfoService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/UserInfoService.java similarity index 94% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/UserInfoService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/UserInfoService.java index cddae299f..3f39d7cca 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/UserInfoService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/UserInfoService.java @@ -15,9 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service; +package cz.muni.ics.openid.connect.service; -import org.mitre.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.model.UserInfo; /** * Interface for UserInfo service diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/WhitelistedSiteService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/WhitelistedSiteService.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/WhitelistedSiteService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/WhitelistedSiteService.java index 420fd4b24..0803febcd 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/WhitelistedSiteService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/WhitelistedSiteService.java @@ -15,11 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service; +package cz.muni.ics.openid.connect.service; import java.util.Collection; -import org.mitre.openid.connect.model.WhitelistedSite; +import cz.muni.ics.openid.connect.model.WhitelistedSite; /** * Interface for WhitelistedSite service diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultApprovedSiteService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultApprovedSiteService.java similarity index 90% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultApprovedSiteService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultApprovedSiteService.java index c3e91f711..1b830d24f 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultApprovedSiteService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultApprovedSiteService.java @@ -15,15 +15,15 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.repository.OAuth2TokenRepository; -import org.mitre.openid.connect.model.ApprovedSite; -import org.mitre.openid.connect.repository.ApprovedSiteRepository; -import org.mitre.openid.connect.service.ApprovedSiteService; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.repository.OAuth2TokenRepository; +import cz.muni.ics.openid.connect.model.ApprovedSite; +import cz.muni.ics.openid.connect.repository.ApprovedSiteRepository; +import cz.muni.ics.openid.connect.service.ApprovedSiteService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -117,7 +117,7 @@ public class DefaultApprovedSiteService implements ApprovedSiteService { /** * @param userId * @return - * @see org.mitre.openid.connect.repository.ApprovedSiteRepository#getByUserId(java.lang.String) + * @see ApprovedSiteRepository#getByUserId(java.lang.String) */ @Override public Collection<ApprovedSite> getByUserId(String userId) { @@ -127,7 +127,7 @@ public class DefaultApprovedSiteService implements ApprovedSiteService { /** * @param clientId * @return - * @see org.mitre.openid.connect.repository.ApprovedSiteRepository#getByClientId(java.lang.String) + * @see ApprovedSiteRepository#getByClientId(java.lang.String) */ @Override public Collection<ApprovedSite> getByClientId(String clientId) { diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultBlacklistedSiteService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultBlacklistedSiteService.java similarity index 72% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultBlacklistedSiteService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultBlacklistedSiteService.java index 65652b6dc..8efa3da0a 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultBlacklistedSiteService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultBlacklistedSiteService.java @@ -18,13 +18,13 @@ /** * */ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; import java.util.Collection; -import org.mitre.openid.connect.model.BlacklistedSite; -import org.mitre.openid.connect.repository.BlacklistedSiteRepository; -import org.mitre.openid.connect.service.BlacklistedSiteService; +import cz.muni.ics.openid.connect.model.BlacklistedSite; +import cz.muni.ics.openid.connect.repository.BlacklistedSiteRepository; +import cz.muni.ics.openid.connect.service.BlacklistedSiteService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -43,7 +43,7 @@ public class DefaultBlacklistedSiteService implements BlacklistedSiteService { private BlacklistedSiteRepository repository; /* (non-Javadoc) - * @see org.mitre.openid.connect.service.BlacklistedSiteService#getAll() + * @see cz.muni.ics.openid.connect.service.BlacklistedSiteService#getAll() */ @Override public Collection<BlacklistedSite> getAll() { @@ -51,7 +51,7 @@ public class DefaultBlacklistedSiteService implements BlacklistedSiteService { } /* (non-Javadoc) - * @see org.mitre.openid.connect.service.BlacklistedSiteService#getById(java.lang.Long) + * @see cz.muni.ics.openid.connect.service.BlacklistedSiteService#getById(java.lang.Long) */ @Override public BlacklistedSite getById(Long id) { @@ -59,7 +59,7 @@ public class DefaultBlacklistedSiteService implements BlacklistedSiteService { } /* (non-Javadoc) - * @see org.mitre.openid.connect.service.BlacklistedSiteService#remove(org.mitre.openid.connect.model.BlacklistedSite) + * @see cz.muni.ics.openid.connect.service.BlacklistedSiteService#remove(cz.muni.ics.openid.connect.model.BlacklistedSite) */ @Override public void remove(BlacklistedSite blacklistedSite) { @@ -67,7 +67,7 @@ public class DefaultBlacklistedSiteService implements BlacklistedSiteService { } /* (non-Javadoc) - * @see org.mitre.openid.connect.service.BlacklistedSiteService#saveNew(org.mitre.openid.connect.model.BlacklistedSite) + * @see cz.muni.ics.openid.connect.service.BlacklistedSiteService#saveNew(cz.muni.ics.openid.connect.model.BlacklistedSite) */ @Override public BlacklistedSite saveNew(BlacklistedSite blacklistedSite) { @@ -75,7 +75,7 @@ public class DefaultBlacklistedSiteService implements BlacklistedSiteService { } /* (non-Javadoc) - * @see org.mitre.openid.connect.service.BlacklistedSiteService#update(org.mitre.openid.connect.model.BlacklistedSite, org.mitre.openid.connect.model.BlacklistedSite) + * @see cz.muni.ics.openid.connect.service.BlacklistedSiteService#update(cz.muni.ics.openid.connect.model.BlacklistedSite, cz.muni.ics.openid.connect.model.BlacklistedSite) */ @Override public BlacklistedSite update(BlacklistedSite oldBlacklistedSite, BlacklistedSite blacklistedSite) { @@ -83,7 +83,7 @@ public class DefaultBlacklistedSiteService implements BlacklistedSiteService { } /* (non-Javadoc) - * @see org.mitre.openid.connect.service.BlacklistedSiteService#isBlacklisted(java.lang.String) + * @see cz.muni.ics.openid.connect.service.BlacklistedSiteService#isBlacklisted(java.lang.String) */ @Override public boolean isBlacklisted(String uri) { diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultOIDCTokenService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultOIDCTokenService.java similarity index 90% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultOIDCTokenService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultOIDCTokenService.java index 2b6fb1ec7..8d345bf9a 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultOIDCTokenService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultOIDCTokenService.java @@ -15,30 +15,30 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; -import static org.mitre.openid.connect.request.ConnectRequestParameters.MAX_AGE; -import static org.mitre.openid.connect.request.ConnectRequestParameters.NONCE; +import static cz.muni.ics.openid.connect.request.ConnectRequestParameters.MAX_AGE; +import static cz.muni.ics.openid.connect.request.ConnectRequestParameters.NONCE; +import cz.muni.ics.jwt.encryption.service.JWTEncryptionAndDecryptionService; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.openid.connect.util.IdTokenHashUtils; +import cz.muni.ics.openid.connect.web.AuthenticationTimeStamper; import java.util.Date; import java.util.Map; import java.util.Set; import java.util.UUID; -import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.jwt.signer.service.impl.ClientKeyCacheService; -import org.mitre.jwt.signer.service.impl.SymmetricKeyJWTValidatorCacheService; -import org.mitre.oauth2.model.AuthenticationHolderEntity; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.repository.AuthenticationHolderRepository; -import org.mitre.oauth2.service.OAuth2TokenEntityService; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.service.OIDCTokenService; -import org.mitre.openid.connect.util.IdTokenHashUtils; -import org.mitre.openid.connect.web.AuthenticationTimeStamper; +import cz.muni.ics.jwt.signer.service.impl.ClientKeyCacheService; +import cz.muni.ics.jwt.signer.service.impl.SymmetricKeyJWTValidatorCacheService; +import cz.muni.ics.oauth2.model.AuthenticationHolderEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.repository.AuthenticationHolderRepository; +import cz.muni.ics.oauth2.service.OAuth2TokenEntityService; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.service.OIDCTokenService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultScopeClaimTranslationService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultScopeClaimTranslationService.java similarity index 89% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultScopeClaimTranslationService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultScopeClaimTranslationService.java index 5c0637a5e..eb6483bfc 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultScopeClaimTranslationService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultScopeClaimTranslationService.java @@ -15,12 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; import java.util.HashSet; import java.util.Set; -import org.mitre.openid.connect.service.ScopeClaimTranslationService; +import cz.muni.ics.openid.connect.service.ScopeClaimTranslationService; import org.springframework.stereotype.Service; import com.google.common.collect.HashMultimap; @@ -68,7 +68,7 @@ public class DefaultScopeClaimTranslationService implements ScopeClaimTranslatio } /* (non-Javadoc) - * @see org.mitre.openid.connect.service.ScopeClaimTranslationService#getClaimsForScope(java.lang.String) + * @see cz.muni.ics.openid.connect.service.ScopeClaimTranslationService#getClaimsForScope(java.lang.String) */ @Override public Set<String> getClaimsForScope(String scope) { @@ -80,7 +80,7 @@ public class DefaultScopeClaimTranslationService implements ScopeClaimTranslatio } /* (non-Javadoc) - * @see org.mitre.openid.connect.service.ScopeClaimTranslationService#getClaimsForScopeSet(java.util.Set) + * @see cz.muni.ics.openid.connect.service.ScopeClaimTranslationService#getClaimsForScopeSet(java.util.Set) */ @Override public Set<String> getClaimsForScopeSet(Set<String> scopes) { diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultUserInfoService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultUserInfoService.java similarity index 81% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultUserInfoService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultUserInfoService.java index ce830d649..cf3c481cb 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultUserInfoService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultUserInfoService.java @@ -15,15 +15,15 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.repository.UserInfoRepository; -import org.mitre.openid.connect.service.PairwiseIdentiferService; -import org.mitre.openid.connect.service.UserInfoService; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.SubjectType; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.repository.UserInfoRepository; +import cz.muni.ics.openid.connect.service.PairwiseIdentiferService; +import cz.muni.ics.openid.connect.service.UserInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultWhitelistedSiteService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultWhitelistedSiteService.java similarity index 90% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultWhitelistedSiteService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultWhitelistedSiteService.java index 3c530b513..decfa2e4e 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultWhitelistedSiteService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DefaultWhitelistedSiteService.java @@ -15,13 +15,13 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; import java.util.Collection; -import org.mitre.openid.connect.model.WhitelistedSite; -import org.mitre.openid.connect.repository.WhitelistedSiteRepository; -import org.mitre.openid.connect.service.WhitelistedSiteService; +import cz.muni.ics.openid.connect.model.WhitelistedSite; +import cz.muni.ics.openid.connect.repository.WhitelistedSiteRepository; +import cz.muni.ics.openid.connect.service.WhitelistedSiteService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DummyResourceSetService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DummyResourceSetService.java similarity index 90% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DummyResourceSetService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DummyResourceSetService.java index ad60243c1..685f3f5f4 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DummyResourceSetService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/DummyResourceSetService.java @@ -14,14 +14,14 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; import java.util.Collection; import java.util.Collections; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.uma.model.ResourceSet; -import org.mitre.uma.service.ResourceSetService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.uma.model.ResourceSet; +import cz.muni.ics.uma.service.ResourceSetService; import org.springframework.stereotype.Service; /** diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/MatchLoginHintsAgainstUsers.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/MatchLoginHintsAgainstUsers.java similarity index 83% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/MatchLoginHintsAgainstUsers.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/MatchLoginHintsAgainstUsers.java index 74d98ea31..49bd99b69 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/MatchLoginHintsAgainstUsers.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/MatchLoginHintsAgainstUsers.java @@ -14,11 +14,11 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.service.LoginHintExtracter; -import org.mitre.openid.connect.service.UserInfoService; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.service.LoginHintExtracter; +import cz.muni.ics.openid.connect.service.UserInfoService; import org.springframework.beans.factory.annotation.Autowired; import com.google.common.base.Strings; @@ -34,7 +34,7 @@ public class MatchLoginHintsAgainstUsers implements LoginHintExtracter { private UserInfoService userInfoService; /* (non-Javadoc) - * @see org.mitre.openid.connect.service.LoginHintTester#useHint(java.lang.String) + * @see cz.muni.ics.openid.connect.service.LoginHintTester#useHint(java.lang.String) */ @Override public String extractHint(String loginHint) { diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/PassAllLoginHints.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/PassAllLoginHints.java similarity index 84% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/PassAllLoginHints.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/PassAllLoginHints.java index b1894466b..be1ba6f13 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/PassAllLoginHints.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/PassAllLoginHints.java @@ -14,9 +14,9 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; -import org.mitre.openid.connect.service.LoginHintExtracter; +import cz.muni.ics.openid.connect.service.LoginHintExtracter; /** * Sends all login hints through to the login page regardless of setup. @@ -27,7 +27,7 @@ import org.mitre.openid.connect.service.LoginHintExtracter; public class PassAllLoginHints implements LoginHintExtracter { /* (non-Javadoc) - * @see org.mitre.openid.connect.service.LoginHintTester#useHint(java.lang.String) + * @see cz.muni.ics.openid.connect.service.LoginHintTester#useHint(java.lang.String) */ @Override public String extractHint(String loginHint) { diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/RemoveLoginHintsWithHTTP.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/RemoveLoginHintsWithHTTP.java similarity index 86% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/RemoveLoginHintsWithHTTP.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/RemoveLoginHintsWithHTTP.java index eab1585c2..ac3c84ff0 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/RemoveLoginHintsWithHTTP.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/RemoveLoginHintsWithHTTP.java @@ -14,9 +14,9 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; -import org.mitre.openid.connect.service.LoginHintExtracter; +import cz.muni.ics.openid.connect.service.LoginHintExtracter; import com.google.common.base.Strings; @@ -29,7 +29,7 @@ import com.google.common.base.Strings; public class RemoveLoginHintsWithHTTP implements LoginHintExtracter { /* (non-Javadoc) - * @see org.mitre.openid.connect.service.LoginHintTester#useHint(java.lang.String) + * @see cz.muni.ics.openid.connect.service.LoginHintTester#useHint(java.lang.String) */ @Override public String extractHint(String loginHint) { diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/UUIDPairwiseIdentiferService.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/UUIDPairwiseIdentiferService.java similarity index 89% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/UUIDPairwiseIdentiferService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/UUIDPairwiseIdentiferService.java index 14b46fcc3..f9b1bc4f8 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/UUIDPairwiseIdentiferService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/service/impl/UUIDPairwiseIdentiferService.java @@ -18,16 +18,16 @@ /** * */ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; import java.util.Set; import java.util.UUID; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.openid.connect.model.PairwiseIdentifier; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.repository.PairwiseIdentifierRepository; -import org.mitre.openid.connect.service.PairwiseIdentiferService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.openid.connect.model.PairwiseIdentifier; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.repository.PairwiseIdentifierRepository; +import cz.muni.ics.openid.connect.service.PairwiseIdentiferService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectTokenEnhancer.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/token/ConnectTokenEnhancer.java similarity index 90% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectTokenEnhancer.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/token/ConnectTokenEnhancer.java index d5b6a9cdc..250b850cc 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectTokenEnhancer.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/token/ConnectTokenEnhancer.java @@ -15,20 +15,20 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.token; +package cz.muni.ics.openid.connect.token; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.service.OIDCTokenService; +import cz.muni.ics.openid.connect.service.UserInfoService; import java.util.Date; import java.util.UUID; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.service.OIDCTokenService; -import org.mitre.openid.connect.service.UserInfoService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.model.UserInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/token/TofuUserApprovalHandler.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/token/TofuUserApprovalHandler.java similarity index 89% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/token/TofuUserApprovalHandler.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/token/TofuUserApprovalHandler.java index 821b1fafb..1d1a66d30 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/token/TofuUserApprovalHandler.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/token/TofuUserApprovalHandler.java @@ -15,13 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.token; - -import static org.mitre.openid.connect.request.ConnectRequestParameters.APPROVED_SITE; -import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT; -import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_CONSENT; -import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_SEPARATOR; +package cz.muni.ics.openid.connect.token; +import cz.muni.ics.openid.connect.model.WhitelistedSite; +import cz.muni.ics.openid.connect.request.ConnectRequestParameters; +import cz.muni.ics.openid.connect.service.WhitelistedSiteService; +import cz.muni.ics.openid.connect.web.AuthenticationTimeStamper; import java.util.Calendar; import java.util.Collection; import java.util.Date; @@ -32,12 +31,9 @@ import java.util.Set; import javax.servlet.http.HttpSession; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.model.ApprovedSite; -import org.mitre.openid.connect.model.WhitelistedSite; -import org.mitre.openid.connect.service.ApprovedSiteService; -import org.mitre.openid.connect.service.WhitelistedSiteService; -import org.mitre.openid.connect.web.AuthenticationTimeStamper; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.model.ApprovedSite; +import cz.muni.ics.openid.connect.service.ApprovedSiteService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.provider.AuthorizationRequest; @@ -131,9 +127,9 @@ public class TofuUserApprovalHandler implements UserApprovalHandler { boolean alreadyApproved = false; // find out if we're supposed to force a prompt on the user or not - String prompt = (String) authorizationRequest.getExtensions().get(PROMPT); - List<String> prompts = Splitter.on(PROMPT_SEPARATOR).splitToList(Strings.nullToEmpty(prompt)); - if (!prompts.contains(PROMPT_CONSENT)) { + String prompt = (String) authorizationRequest.getExtensions().get(ConnectRequestParameters.PROMPT); + List<String> prompts = Splitter.on(ConnectRequestParameters.PROMPT_SEPARATOR).splitToList(Strings.nullToEmpty(prompt)); + if (!prompts.contains(ConnectRequestParameters.PROMPT_CONSENT)) { // if the prompt parameter is set to "consent" then we can't use approved sites or whitelisted sites // otherwise, we need to check them below @@ -150,7 +146,7 @@ public class TofuUserApprovalHandler implements UserApprovalHandler { approvedSiteService.save(ap); String apId = ap.getId().toString(); - authorizationRequest.getExtensions().put(APPROVED_SITE, apId); + authorizationRequest.getExtensions().put(ConnectRequestParameters.APPROVED_SITE, apId); authorizationRequest.setApproved(true); alreadyApproved = true; @@ -227,7 +223,7 @@ public class TofuUserApprovalHandler implements UserApprovalHandler { ApprovedSite newSite = approvedSiteService.createApprovedSite(clientId, userId, timeout, allowedScopes); String newSiteId = newSite.getId().toString(); - authorizationRequest.getExtensions().put(APPROVED_SITE, newSiteId); + authorizationRequest.getExtensions().put(ConnectRequestParameters.APPROVED_SITE, newSiteId); } setAuthTime(authorizationRequest); diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/util/IdTokenHashUtils.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/util/IdTokenHashUtils.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/util/IdTokenHashUtils.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/util/IdTokenHashUtils.java index 789f3ce18..029db1776 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/util/IdTokenHashUtils.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/util/IdTokenHashUtils.java @@ -16,13 +16,13 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.util; +package cz.muni.ics.openid.connect.util; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/AbstractClientEntityView.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/AbstractClientEntityView.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/view/AbstractClientEntityView.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/AbstractClientEntityView.java index 719bfc8d0..f6d2be6ed 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/AbstractClientEntityView.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/AbstractClientEntityView.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.view; +package cz.muni.ics.openid.connect.view; import java.io.IOException; import java.io.Writer; @@ -28,7 +28,7 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.mitre.oauth2.model.PKCEAlgorithm; +import cz.muni.ics.oauth2.model.PKCEAlgorithm; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/ClientEntityViewForAdmins.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/ClientEntityViewForAdmins.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/view/ClientEntityViewForAdmins.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/ClientEntityViewForAdmins.java index 7fe86f7f7..0b1977dab 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/ClientEntityViewForAdmins.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/ClientEntityViewForAdmins.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.view; +package cz.muni.ics.openid.connect.view; import java.util.Set; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/ClientEntityViewForUsers.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/ClientEntityViewForUsers.java similarity index 94% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/view/ClientEntityViewForUsers.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/ClientEntityViewForUsers.java index 11f1e51dc..3219ca4ac 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/ClientEntityViewForUsers.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/ClientEntityViewForUsers.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.view; +package cz.muni.ics.openid.connect.view; import java.util.Set; @@ -46,7 +46,7 @@ public class ClientEntityViewForUsers extends AbstractClientEntityView { public static final String VIEWNAME = "clientEntityViewUsers"; /* (non-Javadoc) - * @see org.mitre.openid.connect.view.AbstractClientEntityView#getExclusionStrategy() + * @see cz.muni.ics.openid.connect.view.AbstractClientEntityView#getExclusionStrategy() */ @Override protected ExclusionStrategy getExclusionStrategy() { diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/ClientInformationResponseView.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/ClientInformationResponseView.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/view/ClientInformationResponseView.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/ClientInformationResponseView.java index a4b245179..2a002199f 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/ClientInformationResponseView.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/ClientInformationResponseView.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.view; +package cz.muni.ics.openid.connect.view; import java.io.IOException; import java.io.Writer; @@ -27,8 +27,8 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.mitre.oauth2.model.RegisteredClient; -import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor; +import cz.muni.ics.oauth2.model.RegisteredClient; +import cz.muni.ics.openid.connect.ClientDetailsEntityJsonProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/HttpCodeView.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/HttpCodeView.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/view/HttpCodeView.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/HttpCodeView.java index bea53cd17..faa61975f 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/HttpCodeView.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/HttpCodeView.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.view; +package cz.muni.ics.openid.connect.view; import java.util.Map; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JWKSetView.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JWKSetView.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/view/JWKSetView.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JWKSetView.java index 351ac657f..01bdb19a3 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JWKSetView.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JWKSetView.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.view; +package cz.muni.ics.openid.connect.view; import java.io.IOException; import java.io.Writer; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JsonApprovedSiteView.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JsonApprovedSiteView.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/view/JsonApprovedSiteView.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JsonApprovedSiteView.java index 4b84f1a8c..acd65186c 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JsonApprovedSiteView.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JsonApprovedSiteView.java @@ -18,8 +18,9 @@ /** * */ -package org.mitre.openid.connect.view; +package cz.muni.ics.openid.connect.view; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; import java.io.IOException; import java.io.Writer; import java.lang.reflect.Type; @@ -28,8 +29,7 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.openid.connect.model.WhitelistedSite; +import cz.muni.ics.openid.connect.model.WhitelistedSite; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JsonEntityView.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JsonEntityView.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/view/JsonEntityView.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JsonEntityView.java index a9e9401c6..f8afdd768 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JsonEntityView.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JsonEntityView.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.view; +package cz.muni.ics.openid.connect.view; import java.io.IOException; import java.io.Writer; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JsonErrorView.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JsonErrorView.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/view/JsonErrorView.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JsonErrorView.java index db21fffb2..6e985fa27 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JsonErrorView.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/JsonErrorView.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.view; +package cz.muni.ics.openid.connect.view; import java.io.IOException; import java.io.Writer; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/UserInfoJWTView.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/UserInfoJWTView.java similarity index 91% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/view/UserInfoJWTView.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/UserInfoJWTView.java index 1ce83dff0..f9da3e875 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/UserInfoJWTView.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/UserInfoJWTView.java @@ -16,8 +16,10 @@ /** * */ -package org.mitre.openid.connect.view; +package cz.muni.ics.openid.connect.view; +import cz.muni.ics.jwt.encryption.service.JWTEncryptionAndDecryptionService; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; @@ -29,12 +31,10 @@ import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.jwt.signer.service.impl.ClientKeyCacheService; -import org.mitre.jwt.signer.service.impl.SymmetricKeyJWTValidatorCacheService; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.jwt.signer.service.impl.ClientKeyCacheService; +import cz.muni.ics.jwt.signer.service.impl.SymmetricKeyJWTValidatorCacheService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/UserInfoView.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/UserInfoView.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/view/UserInfoView.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/UserInfoView.java index 73ca617f9..644da701b 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/UserInfoView.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/view/UserInfoView.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.view; +package cz.muni.ics.openid.connect.view; import java.io.IOException; import java.io.Writer; @@ -27,8 +27,8 @@ import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.service.ScopeClaimTranslationService; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.service.ScopeClaimTranslationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/ApprovedSiteAPI.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ApprovedSiteAPI.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/ApprovedSiteAPI.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ApprovedSiteAPI.java index 1f05baab5..e5baee8c7 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/ApprovedSiteAPI.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ApprovedSiteAPI.java @@ -18,17 +18,17 @@ /** * */ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonApprovedSiteView; +import cz.muni.ics.openid.connect.view.JsonEntityView; +import cz.muni.ics.openid.connect.view.JsonErrorView; import java.security.Principal; import java.util.Collection; -import org.mitre.openid.connect.model.ApprovedSite; -import org.mitre.openid.connect.service.ApprovedSiteService; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonApprovedSiteView; -import org.mitre.openid.connect.view.JsonEntityView; -import org.mitre.openid.connect.view.JsonErrorView; +import cz.muni.ics.openid.connect.model.ApprovedSite; +import cz.muni.ics.openid.connect.service.ApprovedSiteService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/AuthenticationTimeStamper.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/AuthenticationTimeStamper.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/AuthenticationTimeStamper.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/AuthenticationTimeStamper.java index 4b5bd4c2e..51ed441a3 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/AuthenticationTimeStamper.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/AuthenticationTimeStamper.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; import java.io.IOException; import java.util.Date; @@ -28,7 +28,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.mitre.openid.connect.filter.AuthorizationRequestFilter; +import cz.muni.ics.openid.connect.filter.AuthorizationRequestFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/BlacklistAPI.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/BlacklistAPI.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/BlacklistAPI.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/BlacklistAPI.java index 6757df808..2d76720ab 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/BlacklistAPI.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/BlacklistAPI.java @@ -18,16 +18,16 @@ /** * */ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonEntityView; +import cz.muni.ics.openid.connect.view.JsonErrorView; import java.security.Principal; import java.util.Collection; -import org.mitre.openid.connect.model.BlacklistedSite; -import org.mitre.openid.connect.service.BlacklistedSiteService; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonEntityView; -import org.mitre.openid.connect.view.JsonErrorView; +import cz.muni.ics.openid.connect.model.BlacklistedSite; +import cz.muni.ics.openid.connect.service.BlacklistedSiteService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/ClientAPI.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ClientAPI.java similarity index 85% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/ClientAPI.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ClientAPI.java index e2ccb9802..f883299b7 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/ClientAPI.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ClientAPI.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; import com.google.common.base.Strings; import com.google.common.collect.Sets; @@ -36,21 +36,21 @@ import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.JWTParser; +import cz.muni.ics.jwt.assertion.AssertionValidator; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.view.ClientEntityViewForAdmins; +import cz.muni.ics.openid.connect.view.ClientEntityViewForUsers; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonEntityView; +import cz.muni.ics.openid.connect.view.JsonErrorView; import org.eclipse.persistence.exceptions.DatabaseException; -import org.mitre.jwt.assertion.AssertionValidator; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.ClientDetailsEntity.AppType; -import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod; -import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType; -import org.mitre.oauth2.model.PKCEAlgorithm; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.web.AuthenticationUtilities; -import org.mitre.openid.connect.exception.ValidationException; -import org.mitre.openid.connect.view.ClientEntityViewForAdmins; -import org.mitre.openid.connect.view.ClientEntityViewForUsers; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonEntityView; -import org.mitre.openid.connect.view.JsonErrorView; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.AppType; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.AuthMethod; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.SubjectType; +import cz.muni.ics.oauth2.model.PKCEAlgorithm; +import cz.muni.ics.oauth2.web.AuthenticationUtilities; +import cz.muni.ics.openid.connect.exception.ValidationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -74,43 +74,43 @@ import java.sql.SQLIntegrityConstraintViolationException; import java.text.ParseException; import java.util.Collection; -import static org.mitre.oauth2.model.RegisteredClientFields.APPLICATION_TYPE; -import static org.mitre.oauth2.model.RegisteredClientFields.CLAIMS_REDIRECT_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID_ISSUED_AT; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_NAME; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_SECRET; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_SECRET_EXPIRES_AT; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.CONTACTS; -import static org.mitre.oauth2.model.RegisteredClientFields.DEFAULT_ACR_VALUES; -import static org.mitre.oauth2.model.RegisteredClientFields.DEFAULT_MAX_AGE; -import static org.mitre.oauth2.model.RegisteredClientFields.GRANT_TYPES; -import static org.mitre.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ENC; -import static org.mitre.oauth2.model.RegisteredClientFields.ID_TOKEN_SIGNED_RESPONSE_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.INITIATE_LOGIN_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.JWKS; -import static org.mitre.oauth2.model.RegisteredClientFields.JWKS_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.POLICY_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.POST_LOGOUT_REDIRECT_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.REDIRECT_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.REGISTRATION_ACCESS_TOKEN; -import static org.mitre.oauth2.model.RegisteredClientFields.REGISTRATION_CLIENT_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.REQUEST_OBJECT_SIGNING_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.REQUEST_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.REQUIRE_AUTH_TIME; -import static org.mitre.oauth2.model.RegisteredClientFields.RESPONSE_TYPES; -import static org.mitre.oauth2.model.RegisteredClientFields.SCOPE; -import static org.mitre.oauth2.model.RegisteredClientFields.SECTOR_IDENTIFIER_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.SOFTWARE_STATEMENT; -import static org.mitre.oauth2.model.RegisteredClientFields.SUBJECT_TYPE; -import static org.mitre.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_METHOD; -import static org.mitre.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_SIGNING_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.TOS_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ENC; -import static org.mitre.oauth2.model.RegisteredClientFields.USERINFO_SIGNED_RESPONSE_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.APPLICATION_TYPE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLAIMS_REDIRECT_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_ID; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_ID_ISSUED_AT; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_NAME; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_SECRET; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_SECRET_EXPIRES_AT; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CONTACTS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.DEFAULT_ACR_VALUES; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.DEFAULT_MAX_AGE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.GRANT_TYPES; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ENC; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.ID_TOKEN_SIGNED_RESPONSE_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.INITIATE_LOGIN_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.JWKS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.JWKS_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.POLICY_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.POST_LOGOUT_REDIRECT_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REDIRECT_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REGISTRATION_ACCESS_TOKEN; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REGISTRATION_CLIENT_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REQUEST_OBJECT_SIGNING_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REQUEST_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REQUIRE_AUTH_TIME; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.RESPONSE_TYPES; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SCOPE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SECTOR_IDENTIFIER_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SOFTWARE_STATEMENT; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SUBJECT_TYPE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_METHOD; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_SIGNING_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.TOS_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ENC; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.USERINFO_SIGNED_RESPONSE_ALG; /** * @author Michael Jett <mjett@mitre.org> diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/DynamicClientRegistrationEndpoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/DynamicClientRegistrationEndpoint.java similarity index 88% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/DynamicClientRegistrationEndpoint.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/DynamicClientRegistrationEndpoint.java index 30d6159c1..cba52838d 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/DynamicClientRegistrationEndpoint.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/DynamicClientRegistrationEndpoint.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; @@ -26,25 +26,25 @@ import com.nimbusds.jose.JWEAlgorithm; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jwt.JWTClaimsSet; -import org.mitre.jwt.assertion.AssertionValidator; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.ClientDetailsEntity.AppType; -import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod; -import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.RegisteredClient; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.OAuth2TokenEntityService; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.exception.ValidationException; -import org.mitre.openid.connect.service.BlacklistedSiteService; -import org.mitre.openid.connect.service.OIDCTokenService; -import org.mitre.openid.connect.view.ClientInformationResponseView; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonErrorView; +import cz.muni.ics.jwt.assertion.AssertionValidator; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.view.ClientInformationResponseView; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonErrorView; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.AppType; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.AuthMethod; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.SubjectType; +import cz.muni.ics.oauth2.model.RegisteredClient; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.service.OAuth2TokenEntityService; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.ClientDetailsEntityJsonProcessor; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.exception.ValidationException; +import cz.muni.ics.openid.connect.service.BlacklistedSiteService; +import cz.muni.ics.openid.connect.service.OIDCTokenService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -70,43 +70,43 @@ import java.util.HashSet; import java.util.Set; import java.util.concurrent.TimeUnit; -import static org.mitre.oauth2.model.RegisteredClientFields.APPLICATION_TYPE; -import static org.mitre.oauth2.model.RegisteredClientFields.CLAIMS_REDIRECT_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID_ISSUED_AT; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_NAME; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_SECRET; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_SECRET_EXPIRES_AT; -import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.CONTACTS; -import static org.mitre.oauth2.model.RegisteredClientFields.DEFAULT_ACR_VALUES; -import static org.mitre.oauth2.model.RegisteredClientFields.DEFAULT_MAX_AGE; -import static org.mitre.oauth2.model.RegisteredClientFields.GRANT_TYPES; -import static org.mitre.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ENC; -import static org.mitre.oauth2.model.RegisteredClientFields.ID_TOKEN_SIGNED_RESPONSE_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.INITIATE_LOGIN_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.JWKS; -import static org.mitre.oauth2.model.RegisteredClientFields.JWKS_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.POLICY_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.POST_LOGOUT_REDIRECT_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.REDIRECT_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.REGISTRATION_ACCESS_TOKEN; -import static org.mitre.oauth2.model.RegisteredClientFields.REGISTRATION_CLIENT_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.REQUEST_OBJECT_SIGNING_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.REQUEST_URIS; -import static org.mitre.oauth2.model.RegisteredClientFields.REQUIRE_AUTH_TIME; -import static org.mitre.oauth2.model.RegisteredClientFields.RESPONSE_TYPES; -import static org.mitre.oauth2.model.RegisteredClientFields.SCOPE; -import static org.mitre.oauth2.model.RegisteredClientFields.SECTOR_IDENTIFIER_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.SOFTWARE_STATEMENT; -import static org.mitre.oauth2.model.RegisteredClientFields.SUBJECT_TYPE; -import static org.mitre.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_METHOD; -import static org.mitre.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_SIGNING_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.TOS_URI; -import static org.mitre.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ALG; -import static org.mitre.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ENC; -import static org.mitre.oauth2.model.RegisteredClientFields.USERINFO_SIGNED_RESPONSE_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.APPLICATION_TYPE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLAIMS_REDIRECT_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_ID; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_ID_ISSUED_AT; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_NAME; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_SECRET; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_SECRET_EXPIRES_AT; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CLIENT_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.CONTACTS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.DEFAULT_ACR_VALUES; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.DEFAULT_MAX_AGE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.GRANT_TYPES; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.ID_TOKEN_ENCRYPTED_RESPONSE_ENC; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.ID_TOKEN_SIGNED_RESPONSE_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.INITIATE_LOGIN_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.JWKS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.JWKS_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.POLICY_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.POST_LOGOUT_REDIRECT_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REDIRECT_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REGISTRATION_ACCESS_TOKEN; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REGISTRATION_CLIENT_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REQUEST_OBJECT_SIGNING_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REQUEST_URIS; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.REQUIRE_AUTH_TIME; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.RESPONSE_TYPES; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SCOPE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SECTOR_IDENTIFIER_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SOFTWARE_STATEMENT; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.SUBJECT_TYPE; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_METHOD; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_SIGNING_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.TOS_URI; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ALG; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.USERINFO_ENCRYPTED_RESPONSE_ENC; +import static cz.muni.ics.oauth2.model.RegisteredClientFields.USERINFO_SIGNED_RESPONSE_ALG; @Controller @RequestMapping(value = DynamicClientRegistrationEndpoint.URL) diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/EndSessionEndpoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/EndSessionEndpoint.java new file mode 100644 index 000000000..32cf1ddfe --- /dev/null +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/EndSessionEndpoint.java @@ -0,0 +1,224 @@ +/******************************************************************************* + * Copyright 2018 The MIT Internet Trust Consortium + * + * 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 cz.muni.ics.openid.connect.web; + +import com.google.common.base.Strings; +import com.google.common.collect.Iterables; +import com.nimbusds.jwt.JWT; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.JWTParser; +import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; +import cz.muni.ics.oidc.web.WebHtmlClasses; +import cz.muni.ics.oidc.web.controllers.ControllerUtils; +import cz.muni.ics.oidc.web.langs.Localization; +import java.text.ParseException; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import cz.muni.ics.jwt.assertion.impl.SelfAssertionValidator; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.common.exceptions.InvalidClientException; +import org.springframework.security.saml.SAMLLogoutFilter; +import org.springframework.stereotype.Controller; +import org.springframework.util.StringUtils; +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.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_POST_LOGOUT_REDIRECT_URI; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_STATE; +import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_TARGET; + +/** + * End Session Endpoint from OIDC session management. + * <p> + * This is a copy of the original file with modification at the end of processLogout(). + * </p> + * + * @author Martin Kuba <makub@ics.muni.cz> + * @author Dominik Frantisek Bucik <bucik@ics.muni.cz> + */ +@Controller +//TODO: implement according to spec (https://openid.net/specs/openid-connect-rpinitiated-1_0.html) +// other specs: +//TODO: https://openid.net/specs/openid-connect-frontchannel-1_0.html +//TODO: https://openid.net/specs/openid-connect-backchannel-1_0.html +//TODO: https://openid.net/specs/openid-connect-session-1_0.html +public class EndSessionEndpoint { + + public static final String URL = "endsession"; + + private static final String CLIENT_KEY = "client"; + private static final String STATE_KEY = "state"; + private static final String REDIRECT_URI_KEY = "redirectUri"; + + private static final Logger logger = LoggerFactory.getLogger(EndSessionEndpoint.class); + + private final SelfAssertionValidator validator; + private final PerunOidcConfig perunOidcConfig; + private final ClientDetailsEntityService clientService; + private final Localization localization; + private final WebHtmlClasses htmlClasses; + + @Autowired + public EndSessionEndpoint(SelfAssertionValidator validator, + PerunOidcConfig perunOidcConfig, + ClientDetailsEntityService clientService, + Localization localization, + WebHtmlClasses htmlClasses) { + this.validator = validator; + this.perunOidcConfig = perunOidcConfig; + this.clientService = clientService; + this.localization = localization; + this.htmlClasses = htmlClasses; + } + + @RequestMapping(value = "/" + URL, method = RequestMethod.GET) + public String endSession(@RequestParam(value = "id_token_hint", required = false) String idTokenHint, + @RequestParam(value = PARAM_POST_LOGOUT_REDIRECT_URI, required = false) String postLogoutRedirectUri, + @RequestParam(value = STATE_KEY, required = false) String state, + HttpServletRequest request, + HttpSession session, + Authentication auth, Map<String, Object> model) + { + JWTClaimsSet idTokenClaims = null; // pulled from the parsed and validated ID token + ClientDetailsEntity client = null; // pulled from ID token's audience field + + if (!Strings.isNullOrEmpty(postLogoutRedirectUri)) { + session.setAttribute(REDIRECT_URI_KEY, postLogoutRedirectUri); + } + if (!Strings.isNullOrEmpty(state)) { + session.setAttribute(STATE_KEY, state); + } + + // parse the ID token hint to see if it's valid + if (!Strings.isNullOrEmpty(idTokenHint)) { + try { + JWT idToken = JWTParser.parse(idTokenHint); + + if (validator.isValid(idToken)) { + // we issued this ID token, figure out who it's for + idTokenClaims = idToken.getJWTClaimsSet(); + + String clientId = Iterables.getOnlyElement(idTokenClaims.getAudience()); + + client = clientService.loadClientByClientId(clientId); + + // save a reference in the session for us to pick up later + //session.setAttribute("endSession_idTokenHint_claims", idTokenClaims); + session.setAttribute(CLIENT_KEY, client); + } + } catch (ParseException e) { + // it's not a valid ID token, ignore it + logger.debug("Invalid id token hint", e); + } catch (InvalidClientException e) { + // couldn't find the client, ignore it + logger.debug("Invalid client", e); + } + } + + // are we logged in or not? + if (auth == null || !request.isUserInRole("ROLE_USER")) { + // we're not logged in anyway, process the final redirect bits if needed + return processLogout(null, null, request, session); + } else { + logger.info("Logout confirmating for user {} from client {}", auth.getName(), client != null ? client.getClientName() : "unknown"); + // we are logged in, need to prompt the user before we log out + model.put("client", client); + model.put("idToken", idTokenClaims); + + ControllerUtils.setPageOptions(model, request, localization, htmlClasses, perunOidcConfig); + + // display the log out confirmation page + return "logout"; + } + } + + @RequestMapping(value = "/" + URL, method = RequestMethod.POST) + public String processLogout(@RequestParam(value = "approve", required = false) String approved, + @RequestParam(value = "deny", required = false) String deny, + HttpServletRequest request, + HttpSession session) + { + String redirectUri = (String) session.getAttribute(REDIRECT_URI_KEY); + String state = (String) session.getAttribute(STATE_KEY); + ClientDetailsEntity client = (ClientDetailsEntity) session.getAttribute(CLIENT_KEY); + String redirectURL = null; + + // if we have a client AND the client has post-logout redirect URIs + // registered AND the URI given is in that list, then... + if (isUriValid(redirectUri, client)) { + UriComponentsBuilder uri = UriComponentsBuilder.fromHttpUrl(redirectUri); + if (StringUtils.hasText(state)) { + uri = uri.queryParam("state", state); + } + UriComponents uriComponents = uri.build(); + logger.trace("redirect URL: {}", uriComponents); + redirectURL = uriComponents.toString(); + } + + if (redirectURL != null) { + String target = getRedirectUrl(redirectUri, state); + if (StringUtils.hasText(approved)) { + target = getLogoutUrl(target); + logger.trace("redirecting to logout SAML and then {}", target); + return "redirect:" + target; + } else { + logger.trace("redirecting to {}", target); + return "redirect:" + redirectURL; + } + } else { + if (StringUtils.hasText(approved)) { + logger.trace("redirecting to logout SAML only"); + return "redirect:" + getLogoutUrl(null); + } else { + return "logout_denied"; + } + } + } + + private boolean isUriValid(String redirectUri, ClientDetailsEntity client) { + return StringUtils.hasText(redirectUri) + && client != null + && client.getPostLogoutRedirectUris() != null + && client.getPostLogoutRedirectUris().contains(redirectUri); + } + + private String getLogoutUrl(String target) { + UriComponentsBuilder builder = UriComponentsBuilder.fromPath(SAMLLogoutFilter.FILTER_URL); + if (StringUtils.hasText(target)) { + builder.queryParam(PARAM_TARGET, target); + } + return builder.build().toString(); + } + + private String getRedirectUrl(String postLogoutRedirectUri, String state) { + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(postLogoutRedirectUri); + if (StringUtils.hasText(state)) { + builder.queryParam(PARAM_STATE, state); + } + return builder.build().toString(); + } + +} diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/JWKSetPublishingEndpoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/JWKSetPublishingEndpoint.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/JWKSetPublishingEndpoint.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/JWKSetPublishingEndpoint.java index 0c102a549..04d39c01e 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/JWKSetPublishingEndpoint.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/JWKSetPublishingEndpoint.java @@ -15,12 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.openid.connect.view.JWKSetView; import java.util.Map; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.openid.connect.view.JWKSetView; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/ProtectedResourceRegistrationEndpoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ProtectedResourceRegistrationEndpoint.java similarity index 94% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/ProtectedResourceRegistrationEndpoint.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ProtectedResourceRegistrationEndpoint.java index 9e2e89b33..d5b8ed3c7 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/ProtectedResourceRegistrationEndpoint.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ProtectedResourceRegistrationEndpoint.java @@ -13,29 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.view.ClientInformationResponseView; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonErrorView; import java.io.UnsupportedEncodingException; import java.text.ParseException; import java.util.Date; import java.util.HashSet; import java.util.Set; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.RegisteredClient; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.OAuth2TokenEntityService; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.exception.ValidationException; -import org.mitre.openid.connect.service.OIDCTokenService; -import org.mitre.openid.connect.view.ClientInformationResponseView; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonErrorView; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.AuthMethod; +import cz.muni.ics.oauth2.model.RegisteredClient; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.service.OAuth2TokenEntityService; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.ClientDetailsEntityJsonProcessor; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.exception.ValidationException; +import cz.muni.ics.openid.connect.service.OIDCTokenService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/RootController.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/RootController.java similarity index 97% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/RootController.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/RootController.java index f239a800d..0d5475c22 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/RootController.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/RootController.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/ServerConfigInterceptor.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ServerConfigInterceptor.java similarity index 90% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/ServerConfigInterceptor.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ServerConfigInterceptor.java index f16693613..325049f9c 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/ServerConfigInterceptor.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/ServerConfigInterceptor.java @@ -18,13 +18,13 @@ /** * */ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.config.UIConfiguration; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.config.UIConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/UserInfoEndpoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/UserInfoEndpoint.java similarity index 91% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/UserInfoEndpoint.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/UserInfoEndpoint.java index 16950a092..e7874f380 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/UserInfoEndpoint.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/UserInfoEndpoint.java @@ -15,18 +15,18 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.UserInfoJWTView; +import cz.muni.ics.openid.connect.view.UserInfoView; import java.util.List; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.service.UserInfoService; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.UserInfoJWTView; -import org.mitre.openid.connect.view.UserInfoView; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.service.UserInfoService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/UserInfoInterceptor.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/UserInfoInterceptor.java similarity index 94% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/UserInfoInterceptor.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/UserInfoInterceptor.java index e58a1cda2..1f276200e 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/UserInfoInterceptor.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/UserInfoInterceptor.java @@ -18,11 +18,11 @@ /** * */ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; -import org.mitre.openid.connect.model.OIDCAuthenticationToken; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.service.UserInfoService; +import cz.muni.ics.openid.connect.model.OIDCAuthenticationToken; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.service.UserInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolverImpl; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/WhitelistAPI.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/WhitelistAPI.java similarity index 95% rename from openid-connect-server/src/main/java/org/mitre/openid/connect/web/WhitelistAPI.java rename to perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/WhitelistAPI.java index 8450c88ce..85980a96a 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/WhitelistAPI.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/web/WhitelistAPI.java @@ -18,16 +18,16 @@ /** * */ -package org.mitre.openid.connect.web; +package cz.muni.ics.openid.connect.web; +import cz.muni.ics.openid.connect.view.HttpCodeView; +import cz.muni.ics.openid.connect.view.JsonEntityView; +import cz.muni.ics.openid.connect.view.JsonErrorView; import java.security.Principal; import java.util.Collection; -import org.mitre.openid.connect.model.WhitelistedSite; -import org.mitre.openid.connect.service.WhitelistedSiteService; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonEntityView; -import org.mitre.openid.connect.view.JsonErrorView; +import cz.muni.ics.openid.connect.model.WhitelistedSite; +import cz.muni.ics.openid.connect.service.WhitelistedSiteService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/openid-connect-server/src/main/java/org/mitre/uma/model/Claim.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/Claim.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/uma/model/Claim.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/model/Claim.java index aaa88eb56..ed709ae09 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/model/Claim.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/Claim.java @@ -14,10 +14,10 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.model; +package cz.muni.ics.uma.model; import com.google.gson.JsonElement; -import org.mitre.oauth2.model.convert.JsonElementStringConverter; +import cz.muni.ics.oauth2.model.convert.JsonElementStringConverter; import java.util.Set; diff --git a/openid-connect-server/src/main/java/org/mitre/uma/model/ClaimProcessingResult.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/ClaimProcessingResult.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/uma/model/ClaimProcessingResult.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/model/ClaimProcessingResult.java index 8642b1b20..190034aaf 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/model/ClaimProcessingResult.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/ClaimProcessingResult.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.model; +package cz.muni.ics.uma.model; import java.util.Collection; diff --git a/openid-connect-server/src/main/java/org/mitre/uma/model/Permission.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/Permission.java similarity index 98% rename from openid-connect-server/src/main/java/org/mitre/uma/model/Permission.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/model/Permission.java index a384cd9aa..4f6165209 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/model/Permission.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/Permission.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.model; +package cz.muni.ics.uma.model; import java.util.Set; diff --git a/openid-connect-server/src/main/java/org/mitre/uma/model/PermissionTicket.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/PermissionTicket.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/uma/model/PermissionTicket.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/model/PermissionTicket.java index 3bc7040c5..6a2bc48ce 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/model/PermissionTicket.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/PermissionTicket.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.model; +package cz.muni.ics.uma.model; import java.util.Collection; import java.util.Date; diff --git a/openid-connect-server/src/main/java/org/mitre/uma/model/Policy.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/Policy.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/uma/model/Policy.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/model/Policy.java index 064f9e0d8..286bd76eb 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/model/Policy.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/Policy.java @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.model; +package cz.muni.ics.uma.model; import java.util.Collection; import java.util.Set; diff --git a/openid-connect-server/src/main/java/org/mitre/uma/model/ResourceSet.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/ResourceSet.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/uma/model/ResourceSet.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/model/ResourceSet.java index ed73d1c73..bf769718c 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/model/ResourceSet.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/ResourceSet.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.uma.model; +package cz.muni.ics.uma.model; import java.util.Collection; import java.util.HashSet; diff --git a/openid-connect-server/src/main/java/org/mitre/uma/model/SavedRegisteredClient.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/SavedRegisteredClient.java similarity index 92% rename from openid-connect-server/src/main/java/org/mitre/uma/model/SavedRegisteredClient.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/model/SavedRegisteredClient.java index 34bf8c222..26c2c5d3f 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/model/SavedRegisteredClient.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/SavedRegisteredClient.java @@ -14,8 +14,10 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.model; +package cz.muni.ics.uma.model; +import cz.muni.ics.oauth2.model.RegisteredClient; +import cz.muni.ics.uma.model.convert.RegisteredClientStringConverter; import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Convert; @@ -25,9 +27,6 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; -import org.mitre.oauth2.model.RegisteredClient; -import org.mitre.uma.model.convert.RegisteredClientStringConverter; - /** * @author jricher */ diff --git a/openid-connect-server/src/main/java/org/mitre/uma/model/convert/RegisteredClientStringConverter.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/convert/RegisteredClientStringConverter.java similarity index 90% rename from openid-connect-server/src/main/java/org/mitre/uma/model/convert/RegisteredClientStringConverter.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/model/convert/RegisteredClientStringConverter.java index 542cf75d2..54b15dbdd 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/model/convert/RegisteredClientStringConverter.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/model/convert/RegisteredClientStringConverter.java @@ -14,13 +14,13 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.model.convert; +package cz.muni.ics.uma.model.convert; +import cz.muni.ics.openid.connect.ClientDetailsEntityJsonProcessor; import javax.persistence.AttributeConverter; import javax.persistence.Converter; -import org.mitre.oauth2.model.RegisteredClient; -import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor; +import cz.muni.ics.oauth2.model.RegisteredClient; import org.springframework.util.StringUtils; /** diff --git a/openid-connect-server/src/main/java/org/mitre/uma/repository/PermissionRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/repository/PermissionRepository.java similarity index 87% rename from openid-connect-server/src/main/java/org/mitre/uma/repository/PermissionRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/repository/PermissionRepository.java index 2431e3fe7..b0e6baf93 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/repository/PermissionRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/repository/PermissionRepository.java @@ -14,13 +14,13 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.repository; +package cz.muni.ics.uma.repository; import java.util.Collection; -import org.mitre.uma.model.Permission; -import org.mitre.uma.model.PermissionTicket; -import org.mitre.uma.model.ResourceSet; +import cz.muni.ics.uma.model.Permission; +import cz.muni.ics.uma.model.PermissionTicket; +import cz.muni.ics.uma.model.ResourceSet; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/uma/repository/ResourceSetRepository.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/repository/ResourceSetRepository.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/uma/repository/ResourceSetRepository.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/repository/ResourceSetRepository.java index f3aac1da2..74f3c4490 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/repository/ResourceSetRepository.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/repository/ResourceSetRepository.java @@ -14,11 +14,11 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.repository; +package cz.muni.ics.uma.repository; import java.util.Collection; -import org.mitre.uma.model.ResourceSet; +import cz.muni.ics.uma.model.ResourceSet; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/uma/service/ClaimsProcessingService.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/service/ClaimsProcessingService.java similarity index 88% rename from openid-connect-server/src/main/java/org/mitre/uma/service/ClaimsProcessingService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/service/ClaimsProcessingService.java index a8a18a71b..40b092b88 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/service/ClaimsProcessingService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/service/ClaimsProcessingService.java @@ -14,11 +14,11 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.service; +package cz.muni.ics.uma.service; -import org.mitre.uma.model.ClaimProcessingResult; -import org.mitre.uma.model.PermissionTicket; -import org.mitre.uma.model.ResourceSet; +import cz.muni.ics.uma.model.ClaimProcessingResult; +import cz.muni.ics.uma.model.PermissionTicket; +import cz.muni.ics.uma.model.ResourceSet; /** * Processes claims presented during an UMA transaction. diff --git a/openid-connect-server/src/main/java/org/mitre/uma/service/PermissionService.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/service/PermissionService.java similarity index 93% rename from openid-connect-server/src/main/java/org/mitre/uma/service/PermissionService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/service/PermissionService.java index d79dc154a..38d52a9d4 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/service/PermissionService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/service/PermissionService.java @@ -14,12 +14,12 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.service; +package cz.muni.ics.uma.service; import java.util.Set; -import org.mitre.uma.model.PermissionTicket; -import org.mitre.uma.model.ResourceSet; +import cz.muni.ics.uma.model.PermissionTicket; +import cz.muni.ics.uma.model.ResourceSet; import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException; diff --git a/openid-connect-server/src/main/java/org/mitre/uma/service/ResourceSetService.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/service/ResourceSetService.java similarity index 91% rename from openid-connect-server/src/main/java/org/mitre/uma/service/ResourceSetService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/service/ResourceSetService.java index ef76ce1cb..e84448fde 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/service/ResourceSetService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/service/ResourceSetService.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.uma.service; +package cz.muni.ics.uma.service; import java.util.Collection; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.uma.model.ResourceSet; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.uma.model.ResourceSet; /** * Manage registered resource sets at this authorization server. diff --git a/openid-connect-server/src/main/java/org/mitre/uma/service/SavedRegisteredClientService.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/service/SavedRegisteredClientService.java similarity index 89% rename from openid-connect-server/src/main/java/org/mitre/uma/service/SavedRegisteredClientService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/service/SavedRegisteredClientService.java index 4509db9a5..a616cae9f 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/service/SavedRegisteredClientService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/service/SavedRegisteredClientService.java @@ -14,12 +14,12 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.service; +package cz.muni.ics.uma.service; import java.util.Collection; -import org.mitre.oauth2.model.RegisteredClient; -import org.mitre.uma.model.SavedRegisteredClient; +import cz.muni.ics.oauth2.model.RegisteredClient; +import cz.muni.ics.uma.model.SavedRegisteredClient; /** * @author jricher diff --git a/openid-connect-server/src/main/java/org/mitre/uma/service/UmaTokenService.java b/perun-oidc-server/src/main/java/cz/muni/ics/uma/service/UmaTokenService.java similarity index 86% rename from openid-connect-server/src/main/java/org/mitre/uma/service/UmaTokenService.java rename to perun-oidc-server/src/main/java/cz/muni/ics/uma/service/UmaTokenService.java index 1cea187a9..1113899b3 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/service/UmaTokenService.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/uma/service/UmaTokenService.java @@ -14,11 +14,11 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.uma.service; +package cz.muni.ics.uma.service; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.uma.model.PermissionTicket; -import org.mitre.uma.model.Policy; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.uma.model.PermissionTicket; +import cz.muni.ics.uma.model.Policy; import org.springframework.security.oauth2.provider.OAuth2Authentication; /** diff --git a/openid-connect-server/src/main/java/org/mitre/util/JsonUtils.java b/perun-oidc-server/src/main/java/cz/muni/ics/util/JsonUtils.java similarity index 99% rename from openid-connect-server/src/main/java/org/mitre/util/JsonUtils.java rename to perun-oidc-server/src/main/java/cz/muni/ics/util/JsonUtils.java index be4e80e84..80c6cd594 100644 --- a/openid-connect-server/src/main/java/org/mitre/util/JsonUtils.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/util/JsonUtils.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.util; +package cz.muni.ics.util; import java.io.IOException; import java.util.ArrayList; @@ -29,7 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.mitre.oauth2.model.PKCEAlgorithm; +import cz.muni.ics.oauth2.model.PKCEAlgorithm; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/openid-connect-server/src/main/java/org/mitre/util/jpa/JpaUtil.java b/perun-oidc-server/src/main/java/cz/muni/ics/util/jpa/JpaUtil.java similarity index 96% rename from openid-connect-server/src/main/java/org/mitre/util/jpa/JpaUtil.java rename to perun-oidc-server/src/main/java/cz/muni/ics/util/jpa/JpaUtil.java index 1a601ad86..bbf5deaf2 100644 --- a/openid-connect-server/src/main/java/org/mitre/util/jpa/JpaUtil.java +++ b/perun-oidc-server/src/main/java/cz/muni/ics/util/jpa/JpaUtil.java @@ -15,14 +15,14 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.util.jpa; +package cz.muni.ics.util.jpa; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; -import org.mitre.data.PageCriteria; +import cz.muni.ics.data.PageCriteria; /** * @author mfranklin diff --git a/openid-connect-server/src/test/java/org/mitre/data/AbstractPageOperationTemplateTest.java b/perun-oidc-server/src/test/java/cz/muni/ics/data/AbstractPageOperationTemplateTest.java similarity index 99% rename from openid-connect-server/src/test/java/org/mitre/data/AbstractPageOperationTemplateTest.java rename to perun-oidc-server/src/test/java/cz/muni/ics/data/AbstractPageOperationTemplateTest.java index 1bf6d1e3f..062809ffc 100644 --- a/openid-connect-server/src/test/java/org/mitre/data/AbstractPageOperationTemplateTest.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/data/AbstractPageOperationTemplateTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.data; +package cz.muni.ics.data; import java.util.ArrayList; import java.util.Collection; diff --git a/openid-connect-server/src/test/java/org/mitre/discovery/util/TestWebfingerURLNormalizer.java b/perun-oidc-server/src/test/java/cz/muni/ics/discovery/util/TestWebfingerURLNormalizer.java similarity index 99% rename from openid-connect-server/src/test/java/org/mitre/discovery/util/TestWebfingerURLNormalizer.java rename to perun-oidc-server/src/test/java/cz/muni/ics/discovery/util/TestWebfingerURLNormalizer.java index 34b494360..293f6487c 100644 --- a/openid-connect-server/src/test/java/org/mitre/discovery/util/TestWebfingerURLNormalizer.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/discovery/util/TestWebfingerURLNormalizer.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.discovery.util; +package cz.muni.ics.discovery.util; import org.junit.Test; import org.springframework.web.util.UriComponents; diff --git a/openid-connect-server/src/test/java/org/mitre/jose/TestJWKSetKeyStore.java b/perun-oidc-server/src/test/java/cz/muni/ics/jose/TestJWKSetKeyStore.java similarity index 98% rename from openid-connect-server/src/test/java/org/mitre/jose/TestJWKSetKeyStore.java rename to perun-oidc-server/src/test/java/cz/muni/ics/jose/TestJWKSetKeyStore.java index 188923443..baed83a2e 100644 --- a/openid-connect-server/src/test/java/org/mitre/jose/TestJWKSetKeyStore.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/jose/TestJWKSetKeyStore.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.jose; +package cz.muni.ics.jose; import java.io.File; import java.io.FileOutputStream; @@ -24,7 +24,7 @@ import java.util.List; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mitre.jose.keystore.JWKSetKeyStore; +import cz.muni.ics.jose.keystore.JWKSetKeyStore; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; diff --git a/openid-connect-server/src/test/java/org/mitre/jwt/encryption/service/impl/TestDefaultJWTEncryptionAndDecryptionService.java b/perun-oidc-server/src/test/java/cz/muni/ics/jwt/encryption/service/impl/TestDefaultJWTEncryptionAndDecryptionService.java similarity index 99% rename from openid-connect-server/src/test/java/org/mitre/jwt/encryption/service/impl/TestDefaultJWTEncryptionAndDecryptionService.java rename to perun-oidc-server/src/test/java/cz/muni/ics/jwt/encryption/service/impl/TestDefaultJWTEncryptionAndDecryptionService.java index 18134b411..2b60604d7 100644 --- a/openid-connect-server/src/test/java/org/mitre/jwt/encryption/service/impl/TestDefaultJWTEncryptionAndDecryptionService.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/jwt/encryption/service/impl/TestDefaultJWTEncryptionAndDecryptionService.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.jwt.encryption.service.impl; +package cz.muni.ics.jwt.encryption.service.impl; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; @@ -31,7 +31,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.mitre.jose.keystore.JWKSetKeyStore; +import cz.muni.ics.jose.keystore.JWKSetKeyStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/openid-connect-server/src/test/java/org/mitre/oauth2/model/ClientDetailsEntityTest.java b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/model/ClientDetailsEntityTest.java similarity index 96% rename from openid-connect-server/src/test/java/org/mitre/oauth2/model/ClientDetailsEntityTest.java rename to perun-oidc-server/src/test/java/cz/muni/ics/oauth2/model/ClientDetailsEntityTest.java index 3815b2d9a..cf6830d25 100644 --- a/openid-connect-server/src/test/java/org/mitre/oauth2/model/ClientDetailsEntityTest.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/model/ClientDetailsEntityTest.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; import com.google.common.collect.ImmutableSet; import com.nimbusds.jose.EncryptionMethod; @@ -36,7 +36,7 @@ import static org.junit.Assert.assertEquals; public class ClientDetailsEntityTest { /** - * Test method for {@link org.mitre.oauth2.model.ClientDetailsEntity#ClientDetailsEntity()}. + * Test method for {@link ClientDetailsEntity#ClientDetailsEntity()}. */ @Test public void testClientDetailsEntity() { diff --git a/openid-connect-server/src/test/java/org/mitre/oauth2/model/RegisteredClientTest.java b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/model/RegisteredClientTest.java similarity index 95% rename from openid-connect-server/src/test/java/org/mitre/oauth2/model/RegisteredClientTest.java rename to perun-oidc-server/src/test/java/cz/muni/ics/oauth2/model/RegisteredClientTest.java index adb252cd7..8f09c3542 100644 --- a/openid-connect-server/src/test/java/org/mitre/oauth2/model/RegisteredClientTest.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/model/RegisteredClientTest.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.oauth2.model; +package cz.muni.ics.oauth2.model; import com.google.common.collect.ImmutableSet; import com.nimbusds.jose.EncryptionMethod; @@ -36,7 +36,7 @@ import static org.junit.Assert.assertEquals; public class RegisteredClientTest { /** - * Test method for {@link org.mitre.oauth2.model.RegisteredClient#RegisteredClient()}. + * Test method for {@link RegisteredClient#RegisteredClient()}. */ @Test public void testRegisteredClient() { @@ -81,7 +81,7 @@ public class RegisteredClientTest { } /** - * Test method for {@link org.mitre.oauth2.model.RegisteredClient#RegisteredClient(org.mitre.oauth2.model.ClientDetailsEntity)}. + * Test method for {@link RegisteredClient#RegisteredClient(ClientDetailsEntity)}. */ @Test public void testRegisteredClientClientDetailsEntity() { @@ -128,7 +128,7 @@ public class RegisteredClientTest { } /** - * Test method for {@link org.mitre.oauth2.model.RegisteredClient#RegisteredClient(org.mitre.oauth2.model.ClientDetailsEntity, java.lang.String, java.lang.String)}. + * Test method for {@link RegisteredClient#RegisteredClient(ClientDetailsEntity, java.lang.String, java.lang.String)}. */ @Test public void testRegisteredClientClientDetailsEntityStringString() { diff --git a/openid-connect-server/src/test/java/org/mitre/oauth2/repository/impl/TestDatabaseConfiguration.java b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/repository/impl/TestDatabaseConfiguration.java similarity index 94% rename from openid-connect-server/src/test/java/org/mitre/oauth2/repository/impl/TestDatabaseConfiguration.java rename to perun-oidc-server/src/test/java/cz/muni/ics/oauth2/repository/impl/TestDatabaseConfiguration.java index 51ab0f43c..63b9d5b1a 100644 --- a/openid-connect-server/src/test/java/org/mitre/oauth2/repository/impl/TestDatabaseConfiguration.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/repository/impl/TestDatabaseConfiguration.java @@ -1,4 +1,4 @@ -package org.mitre.oauth2.repository.impl; +package cz.muni.ics.oauth2.repository.impl; import static java.nio.charset.StandardCharsets.UTF_8; @@ -45,7 +45,7 @@ public class TestDatabaseConfiguration { @Bean(name = "defaultPersistenceUnit") public FactoryBean<EntityManagerFactory> entityManagerFactory() { LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); - factory.setPackagesToScan("org.mitre", "org.mitre"); + factory.setPackagesToScan("cz.muni.ics"); factory.setPersistenceProviderClass(org.eclipse.persistence.jpa.PersistenceProvider.class); factory.setPersistenceUnitName("test" + System.currentTimeMillis()); factory.setDataSource(dataSource); @@ -67,7 +67,7 @@ public class TestDatabaseConfiguration { public Resource getResource(String location) { String sql; try { - sql = new String(Files.readAllBytes(Paths.get("..", "openid-connect-server-webapp", "src", "main", + sql = new String(Files.readAllBytes(Paths.get("..", "perun-oidc-server-webapp", "src", "main", "resources", "db", "hsql", location)), UTF_8); } catch (IOException e) { throw new RuntimeException("Failed to read sql-script " + location, e); diff --git a/openid-connect-server/src/test/java/org/mitre/oauth2/repository/impl/TestJpaOAuth2TokenRepository.java b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/repository/impl/TestJpaOAuth2TokenRepository.java similarity index 91% rename from openid-connect-server/src/test/java/org/mitre/oauth2/repository/impl/TestJpaOAuth2TokenRepository.java rename to perun-oidc-server/src/test/java/cz/muni/ics/oauth2/repository/impl/TestJpaOAuth2TokenRepository.java index 4ad4b355c..6ab3d5a01 100644 --- a/openid-connect-server/src/test/java/org/mitre/oauth2/repository/impl/TestJpaOAuth2TokenRepository.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/repository/impl/TestJpaOAuth2TokenRepository.java @@ -1,7 +1,11 @@ -package org.mitre.oauth2.repository.impl; +package cz.muni.ics.oauth2.repository.impl; import static org.junit.Assert.assertEquals; +import cz.muni.ics.oauth2.model.AuthenticationHolderEntity; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; +import cz.muni.ics.oauth2.model.SavedUserAuthentication; import java.util.Set; import javax.persistence.EntityManager; @@ -10,10 +14,6 @@ import javax.persistence.PersistenceContext; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.oauth2.model.AuthenticationHolderEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.oauth2.model.SavedUserAuthentication; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; diff --git a/openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestBlacklistAwareRedirectResolver.java b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestBlacklistAwareRedirectResolver.java similarity index 93% rename from openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestBlacklistAwareRedirectResolver.java rename to perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestBlacklistAwareRedirectResolver.java index 5507707f7..51cceef69 100644 --- a/openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestBlacklistAwareRedirectResolver.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestBlacklistAwareRedirectResolver.java @@ -14,21 +14,20 @@ * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; import static org.mockito.Matchers.anyString; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.service.BlacklistedSiteService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.service.BlacklistedSiteService; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.security.oauth2.common.exceptions.InvalidRequestException; -import org.springframework.security.oauth2.provider.ClientDetails; import com.google.common.collect.ImmutableSet; diff --git a/openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultIntrospectionResultAssembler.java b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultIntrospectionResultAssembler.java similarity index 97% rename from openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultIntrospectionResultAssembler.java rename to perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultIntrospectionResultAssembler.java index 423cab6da..24d9e29b4 100644 --- a/openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultIntrospectionResultAssembler.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultIntrospectionResultAssembler.java @@ -13,11 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; import static com.google.common.collect.Sets.newHashSet; import static org.mockito.BDDMockito.given; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; @@ -27,11 +29,9 @@ import java.util.Set; import javax.swing.text.DateFormatter; import org.junit.Test; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.oauth2.service.IntrospectionResultAssembler; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.uma.model.Permission; +import cz.muni.ics.oauth2.service.IntrospectionResultAssembler; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.uma.model.Permission; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.provider.OAuth2Authentication; diff --git a/openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultOAuth2ClientDetailsEntityService.java b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultOAuth2ClientDetailsEntityService.java similarity index 96% rename from openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultOAuth2ClientDetailsEntityService.java rename to perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultOAuth2ClientDetailsEntityService.java index adf060ae0..c98f3525b 100644 --- a/openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultOAuth2ClientDetailsEntityService.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultOAuth2ClientDetailsEntityService.java @@ -15,24 +15,24 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; import com.google.common.collect.Sets; +import cz.muni.ics.oauth2.repository.OAuth2TokenRepository; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.repository.OAuth2ClientRepository; -import org.mitre.oauth2.repository.OAuth2TokenRepository; -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.model.WhitelistedSite; -import org.mitre.openid.connect.service.ApprovedSiteService; -import org.mitre.openid.connect.service.BlacklistedSiteService; -import org.mitre.openid.connect.service.WhitelistedSiteService; -import org.mitre.uma.model.ResourceSet; -import org.mitre.uma.service.ResourceSetService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.repository.OAuth2ClientRepository; +import cz.muni.ics.oauth2.service.SystemScopeService; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.model.WhitelistedSite; +import cz.muni.ics.openid.connect.service.ApprovedSiteService; +import cz.muni.ics.openid.connect.service.BlacklistedSiteService; +import cz.muni.ics.openid.connect.service.WhitelistedSiteService; +import cz.muni.ics.uma.model.ResourceSet; +import cz.muni.ics.uma.service.ResourceSetService; import org.mockito.AdditionalAnswers; import org.mockito.ArgumentMatchers; import org.mockito.InjectMocks; diff --git a/openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultOAuth2ProviderTokenService.java b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultOAuth2ProviderTokenService.java similarity index 97% rename from openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultOAuth2ProviderTokenService.java rename to perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultOAuth2ProviderTokenService.java index a409d15af..5136263a0 100644 --- a/openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultOAuth2ProviderTokenService.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultOAuth2ProviderTokenService.java @@ -15,8 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity; +import cz.muni.ics.oauth2.repository.OAuth2TokenRepository; import java.util.Date; import java.util.HashSet; import java.util.Set; @@ -24,15 +27,12 @@ import java.util.Set; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.oauth2.model.AuthenticationHolderEntity; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.repository.AuthenticationHolderRepository; -import org.mitre.oauth2.repository.OAuth2TokenRepository; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.oauth2.service.SystemScopeService; +import cz.muni.ics.oauth2.model.AuthenticationHolderEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.repository.AuthenticationHolderRepository; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.oauth2.service.SystemScopeService; import org.mockito.InjectMocks; import org.mockito.Matchers; import org.mockito.Mock; diff --git a/openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultSystemScopeService.java b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultSystemScopeService.java similarity index 97% rename from openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultSystemScopeService.java rename to perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultSystemScopeService.java index 808d96b58..7775cc50a 100644 --- a/openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultSystemScopeService.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/oauth2/service/impl/TestDefaultSystemScopeService.java @@ -15,15 +15,15 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.oauth2.service.impl; +package cz.muni.ics.oauth2.service.impl; import java.util.Set; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.oauth2.model.SystemScope; -import org.mitre.oauth2.repository.SystemScopeRepository; +import cz.muni.ics.oauth2.model.SystemScope; +import cz.muni.ics.oauth2.repository.SystemScopeRepository; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/ClientDetailsEntityJsonProcessorTest.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/ClientDetailsEntityJsonProcessorTest.java similarity index 95% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/ClientDetailsEntityJsonProcessorTest.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/ClientDetailsEntityJsonProcessorTest.java index 63a207907..fc9fd5d62 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/ClientDetailsEntityJsonProcessorTest.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/ClientDetailsEntityJsonProcessorTest.java @@ -18,16 +18,16 @@ /** * */ -package org.mitre.openid.connect; +package cz.muni.ics.openid.connect; import com.google.common.collect.ImmutableSet; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.nimbusds.jose.EncryptionMethod; import com.nimbusds.jose.JWEAlgorithm; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.RegisteredClient; import org.junit.Test; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.RegisteredClient; import java.sql.Date; @@ -41,7 +41,7 @@ import static org.junit.Assert.assertTrue; public class ClientDetailsEntityJsonProcessorTest { /** - * Test method for {@link org.mitre.openid.connect.ClientDetailsEntityJsonProcessor#parse(java.lang.String)}. + * Test method for {@link ClientDetailsEntityJsonProcessor#parse(java.lang.String)}. */ @Test public void testParse() { @@ -86,7 +86,7 @@ public class ClientDetailsEntityJsonProcessorTest { } /** - * Test method for {@link org.mitre.openid.connect.ClientDetailsEntityJsonProcessor#parseRegistered(java.lang.String)}. + * Test method for {@link ClientDetailsEntityJsonProcessor#parseRegistered(java.lang.String)}. */ @Test public void testParseRegistered() { @@ -147,7 +147,7 @@ public class ClientDetailsEntityJsonProcessorTest { } /** - * Test method for {@link org.mitre.openid.connect.ClientDetailsEntityJsonProcessor#serialize(org.mitre.oauth2.model.RegisteredClient)}. + * Test method for {@link ClientDetailsEntityJsonProcessor#serialize(RegisteredClient)}. */ @Test public void testSerialize() { diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/assertion/TestJWTBearerAuthenticationProvider.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/assertion/TestJWTBearerAuthenticationProvider.java similarity index 97% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/assertion/TestJWTBearerAuthenticationProvider.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/assertion/TestJWTBearerAuthenticationProvider.java index fde99f499..2d1ec7ab3 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/assertion/TestJWTBearerAuthenticationProvider.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/assertion/TestJWTBearerAuthenticationProvider.java @@ -1,4 +1,4 @@ -package org.mitre.openid.connect.assertion; +package cz.muni.ics.openid.connect.assertion; import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.CoreMatchers.instanceOf; @@ -8,6 +8,10 @@ import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Mockito.when; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.jwt.signer.service.impl.ClientKeyCacheService; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; import java.util.Arrays; import java.util.Date; import java.util.List; @@ -16,12 +20,8 @@ import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.jwt.signer.service.impl.ClientKeyCacheService; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.ClientDetailsEntity.AuthMethod; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/config/ConfigurationPropertiesBeanTest.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/config/ConfigurationPropertiesBeanTest.java similarity index 99% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/config/ConfigurationPropertiesBeanTest.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/config/ConfigurationPropertiesBeanTest.java index 639b295d1..e30e652fb 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/config/ConfigurationPropertiesBeanTest.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/config/ConfigurationPropertiesBeanTest.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.config; +package cz.muni.ics.openid.connect.config; import org.junit.Test; import org.springframework.beans.factory.BeanCreationException; diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/config/ServerConfigurationTest.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/config/ServerConfigurationTest.java similarity index 95% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/config/ServerConfigurationTest.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/config/ServerConfigurationTest.java index 7e7513e08..e10ab9ab2 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/config/ServerConfigurationTest.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/config/ServerConfigurationTest.java @@ -18,7 +18,7 @@ /** * */ -package org.mitre.openid.connect.config; +package cz.muni.ics.openid.connect.config; import org.junit.Test; @@ -62,7 +62,7 @@ public class ServerConfigurationTest { /** - * Test method for {@link org.mitre.openid.connect.config.ServerConfiguration#equals(java.lang.Object)}. + * Test method for {@link ServerConfiguration#equals(java.lang.Object)}. */ @Test public void testEqualsObject() { diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/config/TestJsonMessageSource.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/config/TestJsonMessageSource.java similarity index 96% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/config/TestJsonMessageSource.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/config/TestJsonMessageSource.java index 04d7735d2..a62f94794 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/config/TestJsonMessageSource.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/config/TestJsonMessageSource.java @@ -1,4 +1,4 @@ -package org.mitre.openid.connect.config; +package cz.muni.ics.openid.connect.config; import org.junit.Before; import org.junit.Test; diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultApprovedSiteService.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultApprovedSiteService.java similarity index 89% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultApprovedSiteService.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultApprovedSiteService.java index daf257179..cd06517c8 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultApprovedSiteService.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultApprovedSiteService.java @@ -15,19 +15,19 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.repository.OAuth2TokenRepository; +import cz.muni.ics.openid.connect.repository.ApprovedSiteRepository; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.repository.OAuth2TokenRepository; -import org.mitre.openid.connect.model.ApprovedSite; -import org.mitre.openid.connect.repository.ApprovedSiteRepository; -import org.mitre.openid.connect.service.ApprovedSiteService; +import cz.muni.ics.openid.connect.model.ApprovedSite; +import cz.muni.ics.openid.connect.service.ApprovedSiteService; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultBlacklistedSiteService.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultBlacklistedSiteService.java similarity index 93% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultBlacklistedSiteService.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultBlacklistedSiteService.java index 79656cddd..ee4bf207a 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultBlacklistedSiteService.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultBlacklistedSiteService.java @@ -15,15 +15,15 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; +import cz.muni.ics.openid.connect.repository.BlacklistedSiteRepository; import java.util.Set; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.openid.connect.model.BlacklistedSite; -import org.mitre.openid.connect.repository.BlacklistedSiteRepository; +import cz.muni.ics.openid.connect.model.BlacklistedSite; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultOIDCTokenService.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultOIDCTokenService.java similarity index 89% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultOIDCTokenService.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultOIDCTokenService.java index 01405474c..f31fe4950 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultOIDCTokenService.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultOIDCTokenService.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; import java.util.Date; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; import org.springframework.security.oauth2.provider.OAuth2Request; import com.nimbusds.jose.JWSAlgorithm; @@ -31,7 +31,6 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultUserInfoService.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultUserInfoService.java similarity index 91% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultUserInfoService.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultUserInfoService.java index e5e707083..a0bb24a55 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultUserInfoService.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultUserInfoService.java @@ -18,18 +18,17 @@ /** * */ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.model.DefaultUserInfo; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.repository.UserInfoRepository; +import cz.muni.ics.openid.connect.service.PairwiseIdentiferService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.openid.connect.model.DefaultUserInfo; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.repository.UserInfoRepository; -import org.mitre.openid.connect.service.PairwiseIdentiferService; import org.mockito.InjectMocks; import org.mockito.Matchers; import org.mockito.Mock; @@ -113,29 +112,29 @@ public class TestDefaultUserInfoService { publicClient2 = new ClientDetailsEntity(); publicClient2.setClientId(publicClientId2); - publicClient2.setSubjectType(SubjectType.PUBLIC); + publicClient2.setSubjectType(ClientDetailsEntity.SubjectType.PUBLIC); // pairwise set 1 pairwiseClient1 = new ClientDetailsEntity(); pairwiseClient1.setClientId(pairwiseClientId1); - pairwiseClient1.setSubjectType(SubjectType.PAIRWISE); + pairwiseClient1.setSubjectType(ClientDetailsEntity.SubjectType.PAIRWISE); pairwiseClient1.setSectorIdentifierUri(sectorIdentifier1); pairwiseClient2 = new ClientDetailsEntity(); pairwiseClient2.setClientId(pairwiseClientId2); - pairwiseClient2.setSubjectType(SubjectType.PAIRWISE); + pairwiseClient2.setSubjectType(ClientDetailsEntity.SubjectType.PAIRWISE); pairwiseClient2.setSectorIdentifierUri(sectorIdentifier2); // pairwise set 2 pairwiseClient3 = new ClientDetailsEntity(); pairwiseClient3.setClientId(pairwiseClientId3); - pairwiseClient3.setSubjectType(SubjectType.PAIRWISE); + pairwiseClient3.setSubjectType(ClientDetailsEntity.SubjectType.PAIRWISE); pairwiseClient3.setSectorIdentifierUri(sectorIdentifier3); // pairwise with null sector pairwiseClient4 = new ClientDetailsEntity(); pairwiseClient4.setClientId(pairwiseClientId4); - pairwiseClient4.setSubjectType(SubjectType.PAIRWISE); + pairwiseClient4.setSubjectType(ClientDetailsEntity.SubjectType.PAIRWISE); diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultWhitelistedSiteService.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultWhitelistedSiteService.java similarity index 94% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultWhitelistedSiteService.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultWhitelistedSiteService.java index 40e8d6508..4df27d645 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestDefaultWhitelistedSiteService.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestDefaultWhitelistedSiteService.java @@ -15,13 +15,13 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; +import cz.muni.ics.openid.connect.model.WhitelistedSite; +import cz.muni.ics.openid.connect.repository.WhitelistedSiteRepository; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.openid.connect.model.WhitelistedSite; -import org.mitre.openid.connect.repository.WhitelistedSiteRepository; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestUUIDPairwiseIdentiferService.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestUUIDPairwiseIdentiferService.java similarity index 88% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestUUIDPairwiseIdentiferService.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestUUIDPairwiseIdentiferService.java index 30e9f5f51..fcd07c588 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/service/impl/TestUUIDPairwiseIdentiferService.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/service/impl/TestUUIDPairwiseIdentiferService.java @@ -18,20 +18,19 @@ /** * */ -package org.mitre.openid.connect.service.impl; +package cz.muni.ics.openid.connect.service.impl; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.openid.connect.model.DefaultUserInfo; +import cz.muni.ics.openid.connect.model.PairwiseIdentifier; +import cz.muni.ics.openid.connect.model.UserInfo; +import cz.muni.ics.openid.connect.repository.PairwiseIdentifierRepository; import java.util.Set; import java.util.UUID; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType; -import org.mitre.openid.connect.model.DefaultUserInfo; -import org.mitre.openid.connect.model.PairwiseIdentifier; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.repository.PairwiseIdentifierRepository; import org.mockito.InjectMocks; import org.mockito.Matchers; import org.mockito.Mock; @@ -98,31 +97,31 @@ public class TestUUIDPairwiseIdentiferService { // pairwise set 1 pairwiseClient1 = new ClientDetailsEntity(); pairwiseClient1.setClientId(pairwiseClientId1); - pairwiseClient1.setSubjectType(SubjectType.PAIRWISE); + pairwiseClient1.setSubjectType(ClientDetailsEntity.SubjectType.PAIRWISE); pairwiseClient1.setSectorIdentifierUri(sectorIdentifier1); pairwiseClient2 = new ClientDetailsEntity(); pairwiseClient2.setClientId(pairwiseClientId2); - pairwiseClient2.setSubjectType(SubjectType.PAIRWISE); + pairwiseClient2.setSubjectType(ClientDetailsEntity.SubjectType.PAIRWISE); pairwiseClient2.setSectorIdentifierUri(sectorIdentifier2); // pairwise set 2 pairwiseClient3 = new ClientDetailsEntity(); pairwiseClient3.setClientId(pairwiseClientId3); - pairwiseClient3.setSubjectType(SubjectType.PAIRWISE); + pairwiseClient3.setSubjectType(ClientDetailsEntity.SubjectType.PAIRWISE); pairwiseClient3.setSectorIdentifierUri(sectorIdentifier3); pairwiseClient3.setRedirectUris(pairwiseClient3RedirectUris); // pairwise with null sector pairwiseClient4 = new ClientDetailsEntity(); pairwiseClient4.setClientId(pairwiseClientId4); - pairwiseClient4.setSubjectType(SubjectType.PAIRWISE); + pairwiseClient4.setSubjectType(ClientDetailsEntity.SubjectType.PAIRWISE); pairwiseClient4.setRedirectUris(pairwiseClient4RedirectUris); // pairwise with multiple redirects and no sector (error) pairwiseClient5 = new ClientDetailsEntity(); pairwiseClient5.setClientId(pairwiseClientId5); - pairwiseClient5.setSubjectType(SubjectType.PAIRWISE); + pairwiseClient5.setSubjectType(ClientDetailsEntity.SubjectType.PAIRWISE); pairwiseClient5.setRedirectUris(pairwiseClient5RedirectUris); // saved pairwise identifier from repository @@ -134,7 +133,7 @@ public class TestUUIDPairwiseIdentiferService { } /** - * Test method for {@link org.mitre.openid.connect.service.impl.UUIDPairwiseIdentiferService#getIdentifier(org.mitre.openid.connect.model.UserInfo, org.mitre.oauth2.model.ClientDetailsEntity)}. + * Test method for {@link UUIDPairwiseIdentiferService#getIdentifier(UserInfo, ClientDetailsEntity)}. */ @Test public void testGetIdentifier_existingEqual() { diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/token/TestConnectTokenEnhancer.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/token/TestConnectTokenEnhancer.java similarity index 86% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/token/TestConnectTokenEnhancer.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/token/TestConnectTokenEnhancer.java index 7e1acbfd9..5cb2ae777 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/token/TestConnectTokenEnhancer.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/token/TestConnectTokenEnhancer.java @@ -15,18 +15,17 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.token; +package cz.muni.ics.openid.connect.token; +import cz.muni.ics.jwt.signer.service.JWTSigningAndValidationService; +import cz.muni.ics.oauth2.model.ClientDetailsEntity; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; +import cz.muni.ics.oauth2.service.ClientDetailsEntityService; +import cz.muni.ics.openid.connect.config.ConfigurationPropertiesBean; +import cz.muni.ics.openid.connect.service.OIDCTokenService; +import cz.muni.ics.openid.connect.service.UserInfoService; import java.text.ParseException; -import org.mitre.jwt.signer.service.JWTSigningAndValidationService; -import org.mitre.oauth2.model.ClientDetailsEntity; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.service.ClientDetailsEntityService; -import org.mitre.openid.connect.config.ConfigurationPropertiesBean; -import org.mitre.openid.connect.model.UserInfo; -import org.mitre.openid.connect.service.OIDCTokenService; -import org.mitre.openid.connect.service.UserInfoService; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.OAuth2Request; @@ -40,7 +39,6 @@ import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import com.nimbusds.jose.JWSAlgorithm; -import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.JWTClaimsSet.Builder; @RunWith(MockitoJUnitRunner.class) diff --git a/openid-connect-server/src/test/java/org/mitre/openid/connect/util/TestIdTokenHashUtils.java b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/util/TestIdTokenHashUtils.java similarity index 96% rename from openid-connect-server/src/test/java/org/mitre/openid/connect/util/TestIdTokenHashUtils.java rename to perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/util/TestIdTokenHashUtils.java index b8ccbfd4c..a0f7758bd 100644 --- a/openid-connect-server/src/test/java/org/mitre/openid/connect/util/TestIdTokenHashUtils.java +++ b/perun-oidc-server/src/test/java/cz/muni/ics/openid/connect/util/TestIdTokenHashUtils.java @@ -15,15 +15,15 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package org.mitre.openid.connect.util; +package cz.muni.ics.openid.connect.util; +import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity; import java.text.ParseException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; @@ -43,7 +43,7 @@ import static org.junit.Assert.assertEquals; public class TestIdTokenHashUtils { @Mock - OAuth2AccessTokenEntity mockToken256; + OAuth2AccessTokenEntity mockToken256; @Mock OAuth2AccessTokenEntity mockToken384; @Mock diff --git a/openid-connect-server/src/test/resources/resources/js/locale/en/messages.json b/perun-oidc-server/src/test/resources/resources/js/locale/en/messages.json similarity index 100% rename from openid-connect-server/src/test/resources/resources/js/locale/en/messages.json rename to perun-oidc-server/src/test/resources/resources/js/locale/en/messages.json diff --git a/pom.xml b/pom.xml index aa7792387..8114922b6 100644 --- a/pom.xml +++ b/pom.xml @@ -18,111 +18,55 @@ --> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> - <groupId>org.mitre</groupId> - <artifactId>openid-connect-parent</artifactId> + <groupId>cz.muni.ics</groupId> + <artifactId>perun-oidc-parent</artifactId> <version>2.0.0</version> - <name>MITREid Connect</name> <packaging>pom</packaging> + + <modules> + <module>perun-oidc-server</module> + <module>perun-oidc-server-webapp</module> + </modules> + + <name>CESNET OpenID-Connect-Java-Spring-Server</name> + <description>OpenID Connect Provider server based on Java and Spring. It comes out of the MITREid Connect implementation.</description> + <url>https://github.com/CESNET/OpenID-Connect-Java-Spring-Server.git</url> + <licenses> <license> <name>The Apache Software License, Version 2.0</name> - <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> + <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url> <distribution>repo</distribution> <comments>A business-friendly OSS license</comments> </license> </licenses> - <modules> - <module>openid-connect-server</module> - <module>openid-connect-server-webapp</module> - </modules> - - <scm> - <connection>scm:git:https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server.git</connection> - <developerConnection>scm:git:git@github.com:mitreid-connect/OpenID-Connect-Java-Spring-Server.git</developerConnection> - <url>https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server.git</url> - <tag>HEAD</tag> - </scm> <developers> <developer> - <id>jricher</id> - <name>Justin Richer</name> - <email>jricher@mit.edu</email> + <name>Dominik František Bučík</name> + <email>bucik@ics.muni.cz</email> + <organization>ICS MUNI</organization> + <organizationUrl>https://ics.muni.cz/</organizationUrl> </developer> </developers> - <mailingLists> - <mailingList> - <archive>https://mailman.mit.edu/mailman/listinfo/mitreid-connect</archive> - <name>MITREid Connect Mailing List</name> - <post>mitreid-connect@mit.edu</post> - </mailingList> - </mailingLists> + <scm> + <connection>scm:git:git://github.com/CESNET/OpenID-Connect-Java-Spring-Server.git</connection> + <developerConnection>scm:git:ssh://github.com:CESNET/OpenID-Connect-Java-Spring-Server.git</developerConnection> + <url>https://github.com/CESNET/OpenID-Connect-Java-Spring-Server.git/tree/master</url> + </scm> - <description>A reference implementation of OpenID Connect (http://openid.net/connect/), OAuth 2.0, and UMA built on top of Java, Spring, and Spring Security. The project contains a fully functioning server, client, and utility library.</description> - <url>https://github.com/mitreid-connect</url> - <build> - <pluginManagement> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <version>3.2.0</version> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-war-plugin</artifactId> - <version>3.3.1</version> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> - <version>3.2.1</version> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.8.1</version> - </plugin> - <plugin> - <groupId>org.appfuse.plugins</groupId> - <artifactId>warpath-maven-plugin</artifactId> - <version>3.5.0</version> - </plugin> - </plugins> - </pluginManagement> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> - <executions> - <execution> - <id>attach-sources</id> - <goals> - <goal>jar</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <source>${java-version}</source> - <target>${java-version}</target> - </configuration> - </plugin> - </plugins> - </build> - - <issueManagement> - <url>https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/issues</url> - <system>GitHub Issues</system> - </issueManagement> - <ciManagement> - <system>Travis CI</system> - <url>https://travis-ci.org/mitreid-connect/OpenID-Connect-Java-Spring-Server</url> - </ciManagement> + <repositories> + <repository> + <id>jitpack.io</id> + <url>https://jitpack.io</url> + </repository> + <repository> + <id>Shibboleth</id> + <name>Shibboleth</name> + <url>https://build.shibboleth.net/nexus/content/repositories/releases/</url> + </repository> + </repositories> <properties> <java-version>8</java-version> @@ -134,15 +78,12 @@ <spring-security.version>4.2.20.RELEASE</spring-security.version> <spring-security-oauth2.version>2.5.1.RELEASE</spring-security-oauth2.version> <jackson.version>2.11.4</jackson.version> - <jstl.version>1.2</jstl.version> - <servlet-api.version>2.5</servlet-api.version> <jsp-api.version>2.2</jsp-api.version> <mysql.version>8.0.23</mysql.version> <hsqldb.version>2.4.0</hsqldb.version> <eclipse-persistence.version>2.7.7</eclipse-persistence.version> <javax-persistence.version>2.2.1</javax-persistence.version> <hikari.version>3.4.5</hikari.version> - <logback.version>1.2.3</logback.version> <org.slf4j-version>1.7.30</org.slf4j-version> <log4j-core.version>2.13.3</log4j-core.version> <junit.version>4.13.1</junit.version> @@ -156,14 +97,42 @@ <commons-io.version>2.7</commons-io.version> <javax-annotation-api.version>1.3.2</javax-annotation-api.version> <lombok.version>1.18.18</lombok.version> + <servlet-api.version>2.5</servlet-api.version> + <jstl.version>1.2</jstl.version> + <apache-commons.version>3.9</apache-commons.version> + <jackson-dataformat-yml.verson>2.11.4</jackson-dataformat-yml.verson> + <mariadb-java-client.version>2.7.0</mariadb-java-client.version> + <apache-directory-api.version>2.0.1</apache-directory-api.version> + <janino.version>3.0.12</janino.version> + <logback.verison>1.2.3</logback.verison> + <jul-to-slf4j.version>1.7.30</jul-to-slf4j.version> + <shedlock.version>4.3.1</shedlock.version> + <javax-annotation-api.version>1.3.2</javax-annotation-api.version> + <jakarta-xml-bind-api.version>2.3.3</jakarta-xml-bind-api.version> + <jaxb-runtime.version>2.3.3</jaxb-runtime.version> + <jakarta-servlet-api.version>4.0.4</jakarta-servlet-api.version> + <aspectjweaver.version>1.9.6</aspectjweaver.version> + <spring-aop.version>4.3.30.RELEASE</spring-aop.version> + <spring-context.version>4.3.30.RELEASE</spring-context.version> + <spring-security-saml2.version>1.0.10.RELEASE</spring-security-saml2.version> + <!-- BUILD --> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <java-version>8</java-version> + <maven.compiler.source>${java-version}</maven.compiler.source> + <maven.compiler.target>${java-version}</maven.compiler.target> </properties> <dependencyManagement> <dependencies> <dependency> - <groupId>javax.annotation</groupId> - <artifactId>javax.annotation-api</artifactId> - <version>${javax-annotation-api.version}</version> + <groupId>cz.muni.ics</groupId> + <artifactId>perun-oidc-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>cz.muni.ics</groupId> + <artifactId>perun-oidc-server-webapp</artifactId> + <version>${project.version}</version> </dependency> <!-- Spring --> <dependency> @@ -203,12 +172,6 @@ <artifactId>jstl-api</artifactId> <version>${jstl.version}</version> </dependency> - <dependency> - <groupId>javax.servlet</groupId> - <artifactId>servlet-api</artifactId> - <version>${servlet-api.version}</version> - <scope>compile</scope> - </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> @@ -237,12 +200,6 @@ <artifactId>HikariCP</artifactId> <version>${hikari.version}</version> </dependency> - <!-- Logging --> - <dependency> - <groupId>ch.qos.logback</groupId> - <artifactId>logback-classic</artifactId> - <version>${logback.version}</version> - </dependency> <!-- Test --> <dependency> <groupId>junit</groupId> @@ -297,7 +254,165 @@ <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>${servlet-api.version}</version> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>jstl</artifactId> + <version>${jstl.version}</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>${apache-commons.version}</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.dataformat</groupId> + <artifactId>jackson-dataformat-yaml</artifactId> + <version>${jackson-dataformat-yml.verson}</version> + </dependency> + <!-- MySQL JDBC driver --> + <dependency> + <groupId>org.mariadb.jdbc</groupId> + <artifactId>mariadb-java-client</artifactId> + <version>${mariadb-java-client.version}</version> + </dependency> + <!-- LDAP --> + <dependency> + <groupId>org.apache.directory.api</groupId> + <artifactId>api-all</artifactId> + <version>${apache-directory-api.version}</version> + </dependency> + <!-- logging --> + <dependency> + <groupId>org.codehaus.janino</groupId> + <artifactId>janino</artifactId> + <version>${janino.version}</version> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>${logback.verison}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jul-to-slf4j</artifactId> + <version>${jul-to-slf4j.version}</version> + </dependency> + <dependency> + <groupId>net.javacrumbs.shedlock</groupId> + <artifactId>shedlock-spring</artifactId> + <version>${shedlock.version}</version> + </dependency> + <dependency> + <groupId>net.javacrumbs.shedlock</groupId> + <artifactId>shedlock-provider-jdbc-template</artifactId> + <version>${shedlock.version}</version> + </dependency> + <dependency> + <groupId>javax.annotation</groupId> + <artifactId>javax.annotation-api</artifactId> + <version>${javax-annotation-api.version}</version> + </dependency> + <dependency> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + <version>${jakarta-xml-bind-api.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jaxb</groupId> + <artifactId>jaxb-runtime</artifactId> + <version>${jaxb-runtime.version}</version> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <version>${jakarta-servlet-api.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-aop</artifactId> + <version>${spring-aop.version}</version> + </dependency> + <dependency> + <groupId>org.aspectj</groupId> + <artifactId>aspectjweaver</artifactId> + <version>${aspectjweaver.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + <version>${spring-context.version}</version> + </dependency> + <dependency> + <groupId>org.springframework.security.extensions</groupId> + <artifactId>spring-security-saml2-core</artifactId> + <version>${spring-security-saml2.version}</version> + </dependency> </dependencies> </dependencyManagement> + <build> + <pluginManagement> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>3.2.0</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <version>3.3.1</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <version>3.2.1</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.8.1</version> + </plugin> + <plugin> + <groupId>org.appfuse.plugins</groupId> + <artifactId>warpath-maven-plugin</artifactId> + <version>3.5.0</version> + </plugin> + </plugins> + </pluginManagement> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <executions> + <execution> + <id>attach-sources</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>${java-version}</source> + <target>${java-version}</target> + </configuration> + </plugin> + </plugins> + </build> + </project>