Implemented openid authentication for authorization code request.

Change-Id: I1f93d20315d1da6573a98d92515d5e4ed979fbed
diff --git a/full/Changes b/full/Changes
index 00d2cad..70835d0 100644
--- a/full/Changes
+++ b/full/Changes
@@ -1,116 +1,120 @@
+version 0.60.4
+12/06/2018
+    - implemented OAuth2 authorization code request with OpenID Authentication (margaretha)
+    
 version 0.60.3
 06/06/2018
-	- improved user authentication by using authentication filter for authorization code request (margaretha)
-	- limited client authentication to client id checking in authorization code request (margaretha)
-	- added user_id in the oauth2_access_token database table (margaretha)
-	- implemented OAuth2Authentication provider for token context management (margaretha)
-	- added parameter checking for authorization DAO (margaretha)
-	- added controller tests using OAuth2 access token (margaretha)
-	- added database tables for MySQL (margaretha)
-	- updated JWT library and related codes (margaretha)
-	
+    - improved user authentication by using authentication filter for authorization code request (margaretha)
+    - limited client authentication to client id checking in authorization code request (margaretha)
+    - added user_id in the oauth2_access_token database table (margaretha)
+    - implemented OAuth2Authentication provider for token context management (margaretha)
+    - added parameter checking for authorization DAO (margaretha)
+    - added controller tests using OAuth2 access token (margaretha)
+    - added database tables for MySQL (margaretha)
+    - updated JWT library and related codes (margaretha)    
+    
 version 0.60.2
 03/05/2018
-	- implemented OAuth2 client registration (margaretha)
-	- implemented OAuth2 client authentication (margaretha)
-	- changed virtual corpus search to retrieval (margaretha)
-	- implemented public client deregistration task (margaretha)
-	- added client registration and deregistration tests (margaretha)
-	- implemented confidential client deregistration task (margaretha)
-	- fixed storing client secret (margaretha)
-	- implemented OAuth2 response handler (margaretha)
-	- implemented OAuth2 request access token with client credentials grant (margaretha)
-	- implemented OAuth2 request access token with resource owner password grant (margaretha)
-	- implemented OAuth2 authorization code request (margaretha)
-	- added OAuth2 error codes (margaretha)
-	- added OAuth2 authorization, scope and access token tables for SQLite (margaretha)
-	- implemented OAuth2 authorization, scope and access token DAO (margaretha)
-	- implemented OAuth2 request access token with authorization code grant (margaretha)
-	- added setting default scopes in the config file (margaretha)
-	- fixed loading spring config multiple times in the test suite (margaretha)
-	- added SQLite created_date trigger for access token (margaretha)  
-	- added a join table for access token scopes (margaretha)
-	- added access scopes handling (margaretha)
-	- added tests about request token with authorization code (margaretha)
-	
+    - implemented OAuth2 client registration (margaretha)
+    - implemented OAuth2 client authentication (margaretha)
+    - changed virtual corpus search to retrieval (margaretha)
+    - implemented public client deregistration task (margaretha)
+    - added client registration and deregistration tests (margaretha)
+    - implemented confidential client deregistration task (margaretha)
+    - fixed storing client secret (margaretha)
+    - implemented OAuth2 response handler (margaretha)
+    - implemented OAuth2 request access token with client credentials grant (margaretha)
+    - implemented OAuth2 request access token with resource owner password grant (margaretha)
+    - implemented OAuth2 authorization code request (margaretha)
+    - added OAuth2 error codes (margaretha)
+    - added OAuth2 authorization, scope and access token tables for SQLite (margaretha)
+    - implemented OAuth2 authorization, scope and access token DAO (margaretha)
+    - implemented OAuth2 request access token with authorization code grant (margaretha)
+    - added setting default scopes in the config file (margaretha)
+    - fixed loading spring config multiple times in the test suite (margaretha)
+    - added SQLite created_date trigger for access token (margaretha)  
+    - added a join table for access token scopes (margaretha)
+    - added access scopes handling (margaretha)
+    - added tests about request token with authorization code (margaretha)
+    
 version 0.60.1
 28/03/2018
-	- added admin-related SQL codes (margaretha)
-	- updated AdminDao (margaretha)
-	- added optional username query parameter to group list controller (margaretha) 
-	- fixed non hierarchical URI of kustvakt conf files (margaretha)
-	- added delete group member triggers (margaretha)
-	- added list user-group by username and status for system admin (margaretha)
-	- added user-group status in user-group DTO (margaretha)
-	- added check for hidden groups in user-group tests (margaretha)
-	- added database trigger test on deleting members when deleting group (margaretha)
-	- renamed VC type PREDEFINED to SYSTEM (margaretha)
-	- added VC list controller for system admin (margaretha)
-	- added VC controller tests with for system admin (margaretha) 
-	- added hidden access removal when deleting published VC (margaretha)
-	- added check for hidden groups in VC controller tests (margaretha)
-	- added search user-group controller (margaretha)
-	- removed createdBy from VirtualCorpusJson (margaretha)
-	- moved member role setting from the invitation phase to the after-subscription phase (margaretha)
-	- added member role removal after deleting members (margaretha)
-	- added add and delete member role controllers (margaretha)
-	
+    - added admin-related SQL codes (margaretha)
+    - updated AdminDao (margaretha)
+    - added optional username query parameter to group list controller (margaretha) 
+    - fixed non hierarchical URI of kustvakt conf files (margaretha)
+    - added delete group member triggers (margaretha)
+    - added list user-group by username and status for system admin (margaretha)
+    - added user-group status in user-group DTO (margaretha)
+    - added check for hidden groups in user-group tests (margaretha)
+    - added database trigger test on deleting members when deleting group (margaretha)
+    - renamed VC type PREDEFINED to SYSTEM (margaretha)
+    - added VC list controller for system admin (margaretha)
+    - added VC controller tests with for system admin (margaretha) 
+    - added hidden access removal when deleting published VC (margaretha)
+    - added check for hidden groups in VC controller tests (margaretha)
+    - added search user-group controller (margaretha)
+    - removed createdBy from VirtualCorpusJson (margaretha)
+    - moved member role setting from the invitation phase to the after-subscription phase (margaretha)
+    - added member role removal after deleting members (margaretha)
+    - added add and delete member role controllers (margaretha)
+    
 version 0.60
 14/03/2018
-	- set up mail settings using localhost port 25 (margaretha)
-	- added mail template in kustvakt configuration (margaretha)
-	- added mail settings to readme (margaretha)
-	- disabled email notification for auto group (margaretha)
-	- added metadata retrieval (diewald)
-	- enabled custom implementation for email address retrieval (margaretha)
-	- removed old policy and deprecated code (margaretha)
-	- moved authentication related code to /full (margaretha)
-	- added userRoles attribute to UserGroupDto. (margaretha)
-	- fixed sqlite trigger (margaretha)
-	- fixed member exist error message (margaretha)
-	- fixed member invitation to join deleted group (margaretha)
-	- added checking deleted group (margaretha)
+    - set up mail settings using localhost port 25 (margaretha)
+    - added mail template in kustvakt configuration (margaretha)
+    - added mail settings to readme (margaretha)
+    - disabled email notification for auto group (margaretha)
+    - added metadata retrieval (diewald)
+    - enabled custom implementation for email address retrieval (margaretha)
+    - removed old policy and deprecated code (margaretha)
+    - moved authentication related code to /full (margaretha)
+    - added userRoles attribute to UserGroupDto. (margaretha)
+    - fixed sqlite trigger (margaretha)
+    - fixed member exist error message (margaretha)
+    - fixed member invitation to join deleted group (margaretha)
+    - added checking deleted group (margaretha)
 
-version 0.59.10	
+version 0.59.10    
 20/02/2018 
-	- added sort VC by id (margaretha)
-	- added test cases regarding VC sharing (margaretha)
-	- implemented withdraw VC from publication (margaretha)
-	- added Changes file (margaretha)
-	- implemented add/invite users to group (margaretha)
-	- implemented delete user-group and member tasks (margaretha)
-	- added userMemberStatus in group lists (margaretha)
-	- updated and added SQL test data (margaretha)
-	- added user group related tests (margaretha)
-	- implemented custom configuration for deleting user groups and members (margaretha)
-	- updated library versions and java environment (margaretha)
-	- added expiration time check for member invitation (margaretha)
-	- moved .properties files (margaretha) 
-	- merged changelog file to Changes (margaretha)
-	- updated status codes and error messages to be more detailed (margaretha)
-	- testing mail implementation using embedded jetty jndi (margaretha)
-	- fixed collection rewrite regarding OR operation with other fields (margaretha)
-	- implemented sending mail using spring injection and removed jetty jndi (margaretha)
-	- fixed unrecognized application/json (margaretha)
-	- fixed and updated velocity template (margaretha)
-	
+    - added sort VC by id (margaretha)
+    - added test cases regarding VC sharing (margaretha)
+    - implemented withdraw VC from publication (margaretha)
+    - added Changes file (margaretha)
+    - implemented add/invite users to group (margaretha)
+    - implemented delete user-group and member tasks (margaretha)
+    - added userMemberStatus in group lists (margaretha)
+    - updated and added SQL test data (margaretha)
+    - added user group related tests (margaretha)
+    - implemented custom configuration for deleting user groups and members (margaretha)
+    - updated library versions and java environment (margaretha)
+    - added expiration time check for member invitation (margaretha)
+    - moved .properties files (margaretha) 
+    - merged changelog file to Changes (margaretha)
+    - updated status codes and error messages to be more detailed (margaretha)
+    - testing mail implementation using embedded jetty jndi (margaretha)
+    - fixed collection rewrite regarding OR operation with other fields (margaretha)
+    - implemented sending mail using spring injection and removed jetty jndi (margaretha)
+    - fixed unrecognized application/json (margaretha)
+    - fixed and updated velocity template (margaretha)
+    
 version 0.59.9 
 19/01/2018
-	- restructured basic authentication (margaretha)
-	- fixed AuthenticationException to include authentication scheme (margaretha)
-	- fixed rewrite redundancy in collection rewrite (margaretha)
-	- fixed foundry rewrite for constituents (margaretha)
-	- introduced authentication methods, schemes and tokens (margaretha)
-	- implemented collection rewrite with multiple licenses (margaretha)
-	- fixed foundry rewrite for korap span without wrap node (margaretha)
-	- implemented list user group (margaretha)
-	- implemented delete VC task (margaretha)
-	- implemented create user-group, subscribe to user-groups, unsubscribe to user-groups tasks(margaretha)
-	- fixed handling JSON mapping exception for missing enums (margaretha)
+    - restructured basic authentication (margaretha)
+    - fixed AuthenticationException to include authentication scheme (margaretha)
+    - fixed rewrite redundancy in collection rewrite (margaretha)
+    - fixed foundry rewrite for constituents (margaretha)
+    - introduced authentication methods, schemes and tokens (margaretha)
+    - implemented collection rewrite with multiple licenses (margaretha)
+    - fixed foundry rewrite for korap span without wrap node (margaretha)
+    - implemented list user group (margaretha)
+    - implemented delete VC task (margaretha)
+    - implemented create user-group, subscribe to user-groups, unsubscribe to user-groups tasks(margaretha)
+    - fixed handling JSON mapping exception for missing enums (margaretha)
     - implemented list VC task (margaretha)
     - added KoralQuery in VC lists (margaretha)
-	- implemented edit VC task (margaretha)
-	- implemented publish VC task (margaretha)
+    - implemented edit VC task (margaretha)
+    - implemented publish VC task (margaretha)
     - implemented share VC task (margaretha)
     - implemented list only owned VC task (margaretha) 
     - implemented list VC access task (margaretha)
@@ -123,22 +127,22 @@
     
 version 0.59.8 
 21/09/2017
-	- restructured statistics service (margaretha)
-	- removed deprecated loader codes and tests (margaretha)
-	- removed old Spring java configurations (margaretha)
-	- implemented entity classes for the new database (margaretha)
-	- added MySQL codes regarding VC and for testing (margaretha)
-	- added dao methods regarding VC (margaretha)
-	- added similar SQL codes (to MySQL) for sqlite (margaretha)
-	- added dao methods regarding user groups (margaretha)
-	- restructured web-service codes into controller and logic/business-service(margaretha)
-	- implemented user role and privilege, and added tests (margaretha)
-	- prepared test suite using new database (margaretha)
-	- implemented UserGroupDao and tests (margaretha)
-	- fixed missing exceptions in JsonUtils (margaretha)
-	- restructured web filters and authentication codes (margaretha)
-	- implemented create/store VC (margaretha)
-	- fixed collection rewrite bug regarding availability with operation or (margaretha)    
+    - restructured statistics service (margaretha)
+    - removed deprecated loader codes and tests (margaretha)
+    - removed old Spring java configurations (margaretha)
+    - implemented entity classes for the new database (margaretha)
+    - added MySQL codes regarding VC and for testing (margaretha)
+    - added dao methods regarding VC (margaretha)
+    - added similar SQL codes (to MySQL) for sqlite (margaretha)
+    - added dao methods regarding user groups (margaretha)
+    - restructured web-service codes into controller and logic/business-service(margaretha)
+    - implemented user role and privilege, and added tests (margaretha)
+    - prepared test suite using new database (margaretha)
+    - implemented UserGroupDao and tests (margaretha)
+    - fixed missing exceptions in JsonUtils (margaretha)
+    - restructured web filters and authentication codes (margaretha)
+    - implemented create/store VC (margaretha)
+    - fixed collection rewrite bug regarding availability with operation or (margaretha)    
 
 version 0.59.7
 13/10/2016
diff --git a/full/pom.xml b/full/pom.xml
index 8937594..3bdf5d4 100644
--- a/full/pom.xml
+++ b/full/pom.xml
@@ -3,7 +3,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>de.ids_mannheim.korap</groupId>
 	<artifactId>Kustvakt-full</artifactId>
-	<version>0.60.3</version>
+	<version>0.60.4</version>
 	<properties>
 		<java.version>1.8</java.version>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -296,5 +296,12 @@
 			<artifactId>nimbus-jose-jwt</artifactId>
 			<version>5.10</version>
 		</dependency>
+		
+		<!-- OpenId -->
+		<dependency>
+		    <groupId>com.nimbusds</groupId>
+		    <artifactId>oauth2-oidc-sdk</artifactId>
+		    <version>5.62</version>
+		</dependency>
 	</dependencies>
 </project>
\ No newline at end of file
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AuthorizationDao.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AuthorizationDao.java
index af04f45..6bcb11c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AuthorizationDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AuthorizationDao.java
@@ -28,7 +28,7 @@
     @PersistenceContext
     private EntityManager entityManager;
 
-    public void storeAuthorizationCode (String clientId, String userId,
+    public Authorization storeAuthorizationCode (String clientId, String userId,
             String code, Set<AccessScope> scopes, String redirectURI)
             throws KustvaktException {
         ParameterChecker.checkStringValue(clientId, "client_id");
@@ -45,6 +45,7 @@
 
         entityManager.persist(authCode);
         // what if unique fails
+        return authCode;
     }
 
     public Authorization retrieveAuthorizationCode (String code)
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuAuthorizationService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuAuthorizationService.java
new file mode 100644
index 0000000..9f371eb
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuAuthorizationService.java
@@ -0,0 +1,63 @@
+package de.ids_mannheim.korap.oauth2.oltu.service;
+
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
+import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
+import org.apache.oltu.oauth2.as.response.OAuthASResponse;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.OAuthResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.sun.jersey.api.client.ClientResponse.Status;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.entity.AccessScope;
+import de.ids_mannheim.korap.oauth2.entity.Authorization;
+import de.ids_mannheim.korap.oauth2.service.OAuth2AuthorizationService;
+
+/**
+ * OAuth2 authorization service using Apache Oltu
+ * 
+ * @author margaretha
+ *
+ */
+@Service
+public class OltuAuthorizationService extends OAuth2AuthorizationService {
+
+    @Autowired
+    private OAuthIssuer oauthIssuer;
+
+    /**
+     * Authorization code request does not require client
+     * authentication, but only checks if the client id exists.
+     * 
+     * @param request
+     * @param authzRequest
+     * @param username
+     * @return
+     * @throws KustvaktException
+     * @throws OAuthSystemException
+     */
+    public String requestAuthorizationCode (HttpServletRequest request,
+            OAuthAuthzRequest authzRequest, String username)
+            throws KustvaktException, OAuthSystemException {
+
+        String code = oauthIssuer.authorizationCode();
+        Authorization authorization = createAuthorization(username,
+                authzRequest.getClientId(), authzRequest.getResponseType(),
+                authzRequest.getRedirectURI(), authzRequest.getScopes(), code);
+
+        Set<AccessScope> scopes = authorization.getScopes();
+        String scopeStr = scopeService.convertAccessScopesToString(scopes);
+
+        OAuthResponse oAuthResponse = OAuthASResponse
+                .authorizationResponse(request, Status.FOUND.getStatusCode())
+                .setCode(code).setScope(scopeStr)
+                .location(authorization.getRedirectURI()).buildQueryMessage();
+        return oAuthResponse.getLocationUri();
+    }
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdAuthorizationService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdAuthorizationService.java
new file mode 100644
index 0000000..985a7e8
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdAuthorizationService.java
@@ -0,0 +1,57 @@
+package de.ids_mannheim.korap.oauth2.openid.service;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.springframework.stereotype.Service;
+
+import com.nimbusds.oauth2.sdk.AuthorizationCode;
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
+import com.nimbusds.oauth2.sdk.ResponseType;
+import com.nimbusds.oauth2.sdk.Scope;
+import com.nimbusds.oauth2.sdk.id.ClientID;
+import com.nimbusds.oauth2.sdk.id.State;
+import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.oauth2.entity.Authorization;
+import de.ids_mannheim.korap.oauth2.service.OAuth2AuthorizationService;
+
+@Service
+public class OpenIdAuthorizationService
+        extends OAuth2AuthorizationService {
+
+    public URI requestAuthorizationCode (AuthenticationRequest authRequest,
+            String username) throws KustvaktException {
+
+        ClientID clientId = authRequest.getClientID();
+        URI redirectUri = authRequest.getRedirectionURI();
+        State state = authRequest.getState();
+        Scope scope = authRequest.getScope();
+        ResponseType responseType = authRequest.getResponseType();
+
+        String redirectUriStr =
+                (redirectUri != null) ? redirectUri.toString() : null;
+        Set<String> scopeSet =
+                (scope != null) ? new HashSet<>(scope.toStringList()) : null;
+        AuthorizationCode code = new AuthorizationCode();
+
+        Authorization authorization = createAuthorization(username,
+                clientId.toString(), responseType.toString(), redirectUriStr,
+                scopeSet, code.getValue());
+
+        try {
+            return new AuthenticationSuccessResponse(
+                    new URI(authorization.getRedirectURI()), code, null, null,
+                    state, null, null).toURI();
+        }
+        catch (URISyntaxException e) {
+            throw new KustvaktException(StatusCodes.INVALID_REDIRECT_URI,
+                    "Invalid redirect URI.");
+        }
+    }
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
index b258fc0..2d64aa6 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
@@ -3,20 +3,11 @@
 import java.time.ZonedDateTime;
 import java.util.Set;
 
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
-import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
-import org.apache.oltu.oauth2.as.response.OAuthASResponse;
-import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
-import org.apache.oltu.oauth2.common.message.OAuthResponse;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import com.sun.jersey.api.client.ClientResponse.Status;
-
 import de.ids_mannheim.korap.config.FullConfiguration;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
@@ -26,7 +17,7 @@
 import de.ids_mannheim.korap.oauth2.entity.Authorization;
 import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
 
-@Service
+@Service(value="authorizationService")
 public class OAuth2AuthorizationService {
 
     private static Logger jlog =
@@ -35,9 +26,7 @@
     @Autowired
     private OAuth2ClientService clientService;
     @Autowired
-    private OAuth2ScopeService scopeService;
-    @Autowired
-    private OAuthIssuer oauthIssuer;
+    protected OAuth2ScopeService scopeService;
 
     @Autowired
     private AuthorizationDao authorizationDao;
@@ -49,44 +38,38 @@
      * Authorization code request does not require client
      * authentication, but only checks if the client id exists.
      * 
-     * @param request
-     * @param authzRequest
      * @param username
+     * @param clientId
+     * @param responseType
+     * @param redirectUri
+     * @param scopeSet
+     * @param code
      * @return
      * @throws KustvaktException
-     * @throws OAuthSystemException
      */
-    public OAuthResponse requestAuthorizationCode (HttpServletRequest request,
-            OAuthAuthzRequest authzRequest, String username)
-            throws KustvaktException, OAuthSystemException {
+    public Authorization createAuthorization (String username, String clientId,
+            String responseType, String redirectUri, Set<String> scopeSet,
+            String code) throws KustvaktException {
 
-        checkResponseType(authzRequest.getResponseType());
+        checkResponseType(responseType);
 
-        OAuth2Client client =
-                clientService.authenticateClientId(authzRequest.getClientId());
+        OAuth2Client client = clientService.authenticateClientId(clientId);
 
-        String redirectUri = authzRequest.getRedirectURI();
-        boolean hasRedirectUri = hasRedirectUri(redirectUri);
-        redirectUri = verifyRedirectUri(client, hasRedirectUri, redirectUri);
+        String verifiedRedirectUri = verifyRedirectUri(client, redirectUri);
 
-        String code = oauthIssuer.authorizationCode();
-        Set<String> scopeSet = authzRequest.getScopes();
         if (scopeSet == null || scopeSet.isEmpty()) {
             scopeSet = config.getDefaultAccessScopes();
         }
-        String scopeStr = String.join(" ", scopeSet);
         Set<AccessScope> scopes = scopeService.convertToAccessScope(scopeSet);
 
-        authorizationDao.storeAuthorizationCode(authzRequest.getClientId(),
-                username, code, scopes, authzRequest.getRedirectURI());
+        Authorization authorization = authorizationDao.storeAuthorizationCode(
+                clientId, username, code, scopes, redirectUri);
 
-        return OAuthASResponse
-                .authorizationResponse(request, Status.FOUND.getStatusCode())
-                .setCode(code).setScope(scopeStr).location(redirectUri)
-                .buildQueryMessage();
+        authorization.setRedirectURI(verifiedRedirectUri);
+        return authorization;
     }
 
-    private void checkResponseType (String responseType)
+    public void checkResponseType (String responseType)
             throws KustvaktException {
         if (responseType == null || responseType.isEmpty()) {
             throw new KustvaktException(StatusCodes.MISSING_PARAMETER,
@@ -103,15 +86,6 @@
         }
     }
 
-
-
-    private boolean hasRedirectUri (String redirectURI) {
-        if (redirectURI != null && !redirectURI.isEmpty()) {
-            return true;
-        }
-        return false;
-    }
-
     /**
      * If the request contains a redirect_uri parameter, the server
      * must confirm it is a valid redirect URI.
@@ -132,12 +106,11 @@
      * @return a client's redirect URI
      * @throws KustvaktException
      */
-    private String verifyRedirectUri (OAuth2Client client,
-            boolean hasRedirectUri, String redirectUri)
+    public String verifyRedirectUri (OAuth2Client client, String redirectUri)
             throws KustvaktException {
 
         String registeredUri = client.getRedirectURI();
-        if (hasRedirectUri) {
+        if (redirectUri != null && !redirectUri.isEmpty()) {
             // check if the redirect URI the same as that in DB
             if (!redirectUri.equals(registeredUri)) {
                 throw new KustvaktException(StatusCodes.INVALID_REDIRECT_URI,
@@ -153,7 +126,7 @@
                 redirectUri = registeredUri;
             }
             else {
-                throw new KustvaktException(StatusCodes.MISSING_PARAMETER,
+                throw new KustvaktException(StatusCodes.INVALID_REDIRECT_URI,
                         "redirect_uri is required",
                         OAuth2Error.INVALID_REQUEST);
             }
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
index 2487b45..e4da82b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
@@ -174,11 +174,10 @@
     }
 
 
-    public void deregisterConfidentialClient (OAuthRequest oAuthRequest)
-            throws KustvaktException {
+    public void deregisterConfidentialClient (String clientId,
+            String clientSecret) throws KustvaktException {
 
-        OAuth2Client client = authenticateClient(oAuthRequest.getClientId(),
-                oAuthRequest.getClientSecret());
+        OAuth2Client client = authenticateClient(clientId, clientSecret);
         clientDao.deregisterClient(client);
     }
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java
index eedc744..e6609d4 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java
@@ -39,8 +39,10 @@
 
     @Autowired
     private OAuth2ClientService clientService;
+    
     @Autowired
     private OAuth2AuthorizationService authorizationService;
+    
     @Autowired
     private OAuth2ScopeService scopeService;
     @Autowired
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
index ae53294..4b2e19e 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
@@ -26,7 +26,7 @@
 
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.oauth2.OAuth2AuthorizationRequest;
-import de.ids_mannheim.korap.oauth2.service.OAuth2AuthorizationService;
+import de.ids_mannheim.korap.oauth2.oltu.service.OltuAuthorizationService;
 import de.ids_mannheim.korap.oauth2.service.OAuth2TokenService;
 import de.ids_mannheim.korap.security.context.TokenContext;
 import de.ids_mannheim.korap.web.OAuth2ResponseHandler;
@@ -43,7 +43,7 @@
     @Autowired
     private OAuth2TokenService oAuth2Service;
     @Autowired
-    private OAuth2AuthorizationService authorizationService;
+    private OltuAuthorizationService authorizationService;
 
     /**
      * Requests an authorization code.
@@ -84,10 +84,9 @@
                     new FormRequestWrapper(request, form);
             OAuth2AuthorizationRequest authzRequest =
                     new OAuth2AuthorizationRequest(requestWithForm);
-            OAuthResponse authResponse =
-                    authorizationService.requestAuthorizationCode(
-                            requestWithForm, authzRequest, username);
-            return responseHandler.sendRedirect(authResponse.getLocationUri());
+            String uri = authorizationService.requestAuthorizationCode(
+                    requestWithForm, authzRequest, username);
+            return responseHandler.sendRedirect(uri);
         }
         catch (OAuthSystemException e) {
             throw responseHandler.throwit(e);
@@ -182,14 +181,15 @@
             throw responseHandler.throwit(e);
         }
     }
-    
-//    @POST
-//    @Path("revoke")
-//    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-//    @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
-//    public Response revokeAccessToken (@Context HttpServletRequest request,
-//            @FormParam("grant_type") String grantType,
-//            MultivaluedMap<String, String> form) {
-//        return null;
-//    }
+
+    // @POST
+    // @Path("revoke")
+    // @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    // @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+    // public Response revokeAccessToken (@Context HttpServletRequest
+    // request,
+    // @FormParam("grant_type") String grantType,
+    // MultivaluedMap<String, String> form) {
+    // return null;
+    // }
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java
new file mode 100644
index 0000000..c87516f
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java
@@ -0,0 +1,116 @@
+package de.ids_mannheim.korap.web.controller;
+
+import java.net.URI;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.core.SecurityContext;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+import com.sun.jersey.spi.container.ResourceFilters;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.openid.service.OpenIdAuthorizationService;
+import de.ids_mannheim.korap.security.context.TokenContext;
+import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
+import de.ids_mannheim.korap.web.filter.BlockingFilter;
+import de.ids_mannheim.korap.web.utils.MapUtils;
+
+@Controller
+@Path("/oauth2/openid")
+public class OAuth2WithOpenIdController {
+
+    @Autowired
+    private OpenIdAuthorizationService authzService;
+
+    /**
+     * Required parameters for OpenID authentication requests:
+     * 
+     * <ul>
+     * <li>scope: MUST contain "openid" for OpenID Connect
+     * requests,</li>
+     * <li>response_type,</li>
+     * <li>client_id,</li>
+     * <li>redirect_uri: MUST match a pre-registered redirect uri
+     * during client registration.</li>
+     * </ul>
+     * 
+     * Other parameters:
+     * 
+     * <ul>
+     * <li>state (recommended): Opaque value used to maintain state between the request and the 
+     * callback.</li>
+     * <li>response_mode (optional) : mechanism to be used for returning parameters</li>
+     * <li>nonce (optional): String value used to associate a Client session with an ID Token, 
+     * and to mitigate replay attacks. </li>
+     * <li>display (optional):  specifies how the Authorization Server displays the authentication 
+     * and consent user interface pages</li>
+     * <li>prompt (optional): specifies if the Authorization Server prompts the End-User 
+     * for reauthentication and consent. Defined values: none, login, consent, select_account </li>
+     * <li>max_age (optional): maximum Authentication Age.</li>
+     * <li>ui_locales (optional): preferred languages and scripts for the user interface 
+     * represented as a space-separated list of BCP47 [RFC5646] </li>
+     * <li>id_token_hint (optional): ID Token previously issued by the Authorization Server 
+     * being passed as a hint</li>
+     * <li>login_hint (optional): hint to the Authorization Server about the login identifier 
+     * the End-User might use to log in</li>
+     * <li>acr_values (optional): requested Authentication Context Class Reference values. </li>
+     * </ul>
+     * 
+     * @see OpenID Connect Core 1.0 specification
+     * 
+     * @param request
+     * @param context
+     * @param form
+     * @return a redirect to client redirect uri
+     */
+    @POST
+    @Path("authorize")
+    @ResourceFilters({ AuthenticationFilter.class, BlockingFilter.class })
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+    public Response requestAuthorizationCode (
+            @Context HttpServletRequest request,
+            @Context SecurityContext context,
+            MultivaluedMap<String, String> form) {
+
+        Map<String, String> map = MapUtils.toMap(form);
+        AuthenticationRequest authRequest = null;
+        try {
+            authRequest = AuthenticationRequest.parse(map);
+        }
+        catch (ParseException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+            return null;
+        }
+
+        TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
+        String username = tokenContext.getUsername();
+
+        URI uri = null;
+        try {
+            uri = authzService.requestAuthorizationCode(authRequest, username);
+            // System.out.println(uri.toString());
+        }
+        catch (KustvaktException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        ResponseBuilder builder = Response.temporaryRedirect(uri);
+        return builder.build();
+    }
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
index d272f73..cb00c12 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
@@ -33,8 +33,10 @@
 import de.ids_mannheim.korap.web.utils.FormRequestWrapper;
 
 
-/** Defines controllers for OAuth2 clients, namely applications attempting
- * to access users' resources. 
+/**
+ * Defines controllers for OAuth2 clients, namely applications
+ * attempting
+ * to access users' resources.
  * 
  * @author margaretha
  *
@@ -48,20 +50,29 @@
     @Autowired
     private OAuth2ResponseHandler responseHandler;
 
-    /** Registers a client application. Before starting an OAuth process, 
-     * client applications have to be registered first. Only registered
-     * users are allowed to register client applications. After registration,
-     * the client will receive a client_id and a client_secret, if the client 
-     * is confidential (capable of storing the client_secret), that are needed 
+    /**
+     * Registers a client application. Before starting an OAuth
+     * process,
+     * client applications have to be registered first. Only
+     * registered
+     * users are allowed to register client applications. After
+     * registration,
+     * the client will receive a client_id and a client_secret, if the
+     * client
+     * is confidential (capable of storing the client_secret), that
+     * are needed
      * in the authorization process.
      * 
      * From RFC 6749:
-     * The authorization server SHOULD document the size of any identifier 
+     * The authorization server SHOULD document the size of any
+     * identifier
      * it issues.
      * 
      * @param context
-     * @param clientJson a JSON object describing the client
-     * @return client_id and client_secret if the client type is confidential
+     * @param clientJson
+     *            a JSON object describing the client
+     * @return client_id and client_secret if the client type is
+     *         confidential
      * 
      * @see OAuth2ClientJson
      */
@@ -85,11 +96,13 @@
     }
 
 
-    /** Deregisters a public client via owner authentication.
+    /**
+     * Deregisters a public client via owner authentication.
      * 
      * 
      * @param securityContext
-     * @param clientId the client id
+     * @param clientId
+     *            the client id
      * @return HTTP Response OK if successful.
      */
     @DELETE
@@ -112,7 +125,8 @@
     }
 
 
-    /** Deregisters confidential clients. Clients must authenticate. 
+    /**
+     * Deregisters confidential clients. Clients must authenticate.
      * 
      * @param securityContext
      * @param request
@@ -130,7 +144,8 @@
             OAuthRequest oAuthRequest = new OAuth2DeregisterClientRequest(
                     new FormRequestWrapper(request, form));
 
-            clientService.deregisterConfidentialClient(oAuthRequest);
+            clientService.deregisterConfidentialClient(
+                    oAuthRequest.getClientId(), oAuthRequest.getClientSecret());
             return Response.ok().build();
         }
         catch (KustvaktException e) {
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/utils/MapUtils.java b/full/src/main/java/de/ids_mannheim/korap/web/utils/MapUtils.java
new file mode 100644
index 0000000..df2dfc1
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/web/utils/MapUtils.java
@@ -0,0 +1,30 @@
+package de.ids_mannheim.korap.web.utils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+/**
+ * @author margaretha
+ *
+ */
+public class MapUtils {
+
+    public static Map<String, String> toMap (
+            MultivaluedMap<String, String> multivaluedMap) {
+        
+        Set<String> keySet = multivaluedMap.keySet();
+        Map<String, String> map = new HashMap<String, String>(keySet.size());
+        
+        for (String key :  keySet){
+            List<String> values = multivaluedMap.get(key);
+            String value = values.stream().collect(Collectors.joining(" "));
+            map.put(key, value);
+        }
+        return map;
+    }
+}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
new file mode 100644
index 0000000..da84a06
--- /dev/null
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
@@ -0,0 +1,59 @@
+package de.ids_mannheim.korap.web.controller;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.net.URI;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.http.entity.ContentType;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.google.common.net.HttpHeaders;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+
+import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
+import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.SpringJerseyTest;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+
+public class OAuth2OpenIdControllerTest extends SpringJerseyTest {
+
+    @Autowired
+    private HttpAuthorizationHandler handler;
+
+    @Test
+    public void testAuthorize () throws UniformInterfaceException,
+            ClientHandlerException, KustvaktException {
+
+        String redirectUri =
+                "https://korap.ids-mannheim.de/confidential/redirect";
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("response_type", "code");
+        form.add("scope", "openid");
+        form.add("redirect_uri", redirectUri);
+        form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+
+        ClientResponse response = resource().path("oauth2").path("openid")
+                .path("authorize")
+                .header(Attributes.AUTHORIZATION,
+                        handler.createBasicAuthorizationHeaderValue("dory",
+                                "password"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .header(HttpHeaders.CONTENT_TYPE,
+                        ContentType.APPLICATION_FORM_URLENCODED)
+                .entity(form).post(ClientResponse.class);
+
+        URI location = response.getLocation();
+
+        assertEquals(redirectUri, location.getScheme() + "://"
+                + location.getHost() + location.getPath());
+        assertTrue(location.getQuery().startsWith("code"));
+    }
+
+}
diff --git a/full/src/test/resources/kustvakt-test.conf b/full/src/test/resources/kustvakt-test.conf
index d9eda87..ebfb216 100644
--- a/full/src/test/resources/kustvakt-test.conf
+++ b/full/src/test/resources/kustvakt-test.conf
@@ -50,7 +50,7 @@
 oauth.native.client.host=korap.ids-mannheim.de
 oauth2.max.attempts = 2
 # -- scopes separated by space
-oauth2.default.scopes = read_username read_email 
+oauth2.default.scopes = openid read_username read_email 
 oauth2.client.credentials.scopes = read_client_info
 
 # JWT