<NME> LessStrictRedirectUriAuthorizationCodeTokenGranterTest.groovy
<BEF> ADDFILE
<MSG> moved authn and authz classes to auth-server project

<DFF> @@ -0,0 +1,123 @@
+package org.osiam.security.helper
+
+import org.springframework.security.oauth2.common.exceptions.InvalidClientException
+import org.springframework.security.oauth2.common.exceptions.InvalidGrantException
+import org.springframework.security.oauth2.common.exceptions.OAuth2Exception
+import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException
+import org.springframework.security.oauth2.provider.AuthorizationRequest
+import org.springframework.security.oauth2.provider.ClientDetailsService
+import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices
+import org.springframework.security.oauth2.provider.code.AuthorizationRequestHolder
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices
+import spock.lang.Specification
+
+class LessStrictRedirectUriAuthorizationCodeTokenGranterTest extends Specification {
+    def tokenService = Mock(AuthorizationServerTokenServices)
+    def clientDetailsService = Mock(ClientDetailsService)
+    def authzCodeServices = Mock(AuthorizationCodeServices)
+    def underTest = new LessStrictRedirectUriAuthorizationCodeTokenGranter(tokenService, clientDetailsService)
+    AuthorizationRequest authzRequest = Mock(AuthorizationRequest)
+    AuthorizationRequestHolder storedAuth = Mock(AuthorizationRequestHolder)
+    AuthorizationRequest authNRequest = Mock(AuthorizationRequest)
+    def pendingRedirectUri = "localhost:unso"
+
+    def setup(){
+
+        authzCodeServices.consumeAuthorizationCode("12345") >> storedAuth
+        storedAuth.getAuthenticationRequest() >> authNRequest
+        authNRequest.getAuthorizationParameters() >> [redirect_uri: pendingRedirectUri]
+        underTest.authorizationCodeServices = authzCodeServices
+        authNRequest.getRedirectUri() >> pendingRedirectUri
+
+    }
+    def set_redirect_uri(redirect_uri){
+        authzRequest.getAuthorizationParameters() >> [code:"12345", redirect_uri: redirect_uri]
+    }
+
+    def "should continue if the pending redirect uri is equal to the send redirect uri"(){
+        given:
+          set_redirect_uri(pendingRedirectUri)
+
+        when:
+          def result = underTest.getOAuth2Authentication(authzRequest)
+        then:
+        result
+    }
+
+    def "should continue if the pending redirect uri starts with the send redirect uri"(){
+        given:
+        set_redirect_uri("localhost")
+
+        when:
+        def result = underTest.getOAuth2Authentication(authzRequest)
+        then:
+        result
+    }
+
+    def "should continue if the pending redirect uri is null"(){
+        given:
+        authNRequest.getAuthorizationParameters() >> [redirect_uri: null]
+        set_redirect_uri("localhost")
+        when:
+        def result = underTest.getOAuth2Authentication(authzRequest)
+        then:
+
+        result
+    }
+
+    def "should abort if the send redirect uri is null but the pending is not"(){
+        given:
+        set_redirect_uri(null)
+        when:
+        underTest.getOAuth2Authentication(authzRequest)
+        then:
+        def e = thrown(RedirectMismatchException)
+        e.message == "Redirect URI mismatch."
+    }
+
+    def "should abort if the pending redirect uri doesn't starts with the send redirect uri"(){
+        given:
+        set_redirect_uri("localhorst")
+
+        when:
+        underTest.getOAuth2Authentication(authzRequest)
+        then:
+        def e = thrown(RedirectMismatchException)
+        e.message == "Redirect URI mismatch."
+    }
+
+    def "should abort if client_id miss matches"(){
+        given:
+        set_redirect_uri("localhost")
+        authNRequest.getClientId() >> "client_id"
+        authzRequest.getClientId() >> "clientid"
+
+        when:
+        underTest.getOAuth2Authentication(authzRequest)
+        then:
+        def e = thrown(InvalidClientException)
+        e.message == "Client ID mismatch"
+    }
+
+    def "should abort if no authorization code got submitted"(){
+        given:
+        authzRequest.getAuthorizationParameters() >> [code:null]
+
+        when:
+        underTest.getOAuth2Authentication(authzRequest)
+        then:
+        def e = thrown(OAuth2Exception)
+        e.message == "An authorization code must be supplied."
+    }
+
+    def "should abort if no storedAuth got found"(){
+        given:
+        authzRequest.getAuthorizationParameters() >> [code:"123456"]
+
+        when:
+        underTest.getOAuth2Authentication(authzRequest)
+        then:
+        def e = thrown(InvalidGrantException)
+        e.message == "Invalid authorization code: 123456"
+    }
+}

{'commit': 'diff --git a/auth-server/src/main/java/org/osiam/security/authentication/AuthenticationBean.java b/auth-server/src/main/java/org/osiam/security/authentication/AuthenticationBean.java\nnew file mode 100644\nindex 00000000..c3783bbe\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/authentication/AuthenticationBean.java\n@@ -0,0 +1,43 @@\n+/*\n+ * Copyright (C) 2013 tarent AG\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining\n+ * a copy of this software and associated documentation files (the\n+ * "Software"), to deal in the Software without restriction, including\n+ * without limitation the rights to use, copy, modify, merge, publish,\n+ * distribute, sublicense, and/or sell copies of the Software, and to\n+ * permit persons to whom the Software is furnished to do so, subject to\n+ * the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be\n+ * included in all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+ */\n+\n+package org.osiam.security.authentication;\n+\n+import org.springframework.security.core.userdetails.UserDetails;\n+import org.springframework.security.core.userdetails.UserDetailsService;\n+import org.springframework.stereotype.Component;\n+\n+@Component("userDetailsService")\n+/**\n+ * Mainly used for demonstration, it is used to validate the user login, before he grants or denies the client access\n+ * to a resource.\n+ */\n+public class AuthenticationBean implements UserDetailsService {\n+\n+    @Override\n+    public UserDetails loadUserByUsername(final String username) {\n+        return null;\n+        //TODO: call /authentication/User on resource server side\n+        //return userDAO.getByUsername(username);\n+    }\n+}\ndiff --git a/auth-server/src/main/java/org/osiam/security/authentication/ClientDetailsLoadingBean.java b/auth-server/src/main/java/org/osiam/security/authentication/ClientDetailsLoadingBean.java\nnew file mode 100644\nindex 00000000..4f8abc28\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/authentication/ClientDetailsLoadingBean.java\n@@ -0,0 +1,44 @@\n+/*\n+ * Copyright (C) 2013 tarent AG\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining\n+ * a copy of this software and associated documentation files (the\n+ * "Software"), to deal in the Software without restriction, including\n+ * without limitation the rights to use, copy, modify, merge, publish,\n+ * distribute, sublicense, and/or sell copies of the Software, and to\n+ * permit persons to whom the Software is furnished to do so, subject to\n+ * the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be\n+ * included in all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+ */\n+\n+package org.osiam.security.authentication;\n+\n+import org.springframework.security.oauth2.provider.ClientDetails;\n+import org.springframework.security.oauth2.provider.ClientDetailsService;\n+import org.springframework.stereotype.Component;\n+\n+\n+/**\n+ * This class is used by clientAuthenticationManager in Spring to authenticate a client when trading an auth_code to an\n+ * access_token.\n+ */\n+@Component("clientDetails")\n+public class ClientDetailsLoadingBean implements ClientDetailsService {\n+\n+    @Override\n+    public ClientDetails loadClientByClientId(final String clientId) {\n+        return null;\n+        //TODO: call /authentication/Client on resource server side\n+        //return clientDao.getClient(clientId);\n+    }\n+}\n\\ No newline at end of file\ndiff --git a/auth-server/src/main/java/org/osiam/security/authentication/package-info.java b/auth-server/src/main/java/org/osiam/security/authentication/package-info.java\nnew file mode 100644\nindex 00000000..7d58a067\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/authentication/package-info.java\n@@ -0,0 +1,6 @@\n+/**\n+ * org.osiam.security.authentication is a group of classes which are needed by spring-security to authenticate an User\n+ * and clients.\n+ *\n+ */\n+package org.osiam.security.authentication;\n\\ No newline at end of file\ndiff --git a/auth-server/src/main/java/org/osiam/security/authorization/DynamicHTTPMethodScopeEnhancer.java b/auth-server/src/main/java/org/osiam/security/authorization/DynamicHTTPMethodScopeEnhancer.java\nnew file mode 100644\nindex 00000000..678431cb\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/authorization/DynamicHTTPMethodScopeEnhancer.java\n@@ -0,0 +1,83 @@\n+/*\n+ * Copyright (C) 2013 tarent AG\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining\n+ * a copy of this software and associated documentation files (the\n+ * "Software"), to deal in the Software without restriction, including\n+ * without limitation the rights to use, copy, modify, merge, publish,\n+ * distribute, sublicense, and/or sell copies of the Software, and to\n+ * permit persons to whom the Software is furnished to do so, subject to\n+ * the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be\n+ * included in all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+ */\n+\n+package org.osiam.security.authorization;\n+\n+import org.springframework.security.access.AccessDecisionVoter;\n+import org.springframework.security.access.ConfigAttribute;\n+import org.springframework.security.access.SecurityConfig;\n+import org.springframework.security.core.Authentication;\n+import org.springframework.security.web.FilterInvocation;\n+\n+import java.util.Collection;\n+import java.util.HashSet;\n+import java.util.Locale;\n+import java.util.Set;\n+\n+/**\n+ * This AccessDecisionVoter is based upon an other AccessDecisionVoter given in the constructor.\n+ * <p/>\n+ * The only purpose of this class is to enhance attributes with a SCOPE_HTTP-Method in vote when SCOPE_DYNAMIC is set.\n+ *\n+ * @author phil\n+ */\n+public class DynamicHTTPMethodScopeEnhancer implements AccessDecisionVoter<Object> {\n+\n+    private final ConfigAttribute dynamic = new SecurityConfig("SCOPE_DYNAMIC");\n+    private final AccessDecisionVoter<Object> basedOnVoter;\n+\n+    public DynamicHTTPMethodScopeEnhancer(final AccessDecisionVoter<Object> basedOnVoter) {\n+        this.basedOnVoter = basedOnVoter;\n+    }\n+\n+\n+    @Override\n+    public boolean supports(final ConfigAttribute attribute) {\n+        return basedOnVoter.supports(attribute);\n+    }\n+\n+    @Override\n+    public boolean supports(final Class<?> clazz) {\n+        return basedOnVoter.supports(clazz);\n+    }\n+\n+    @Override\n+    public int vote(final Authentication authentication, final Object object, final Collection<ConfigAttribute> attributes) {\n+        Set<ConfigAttribute> dynamicConfigs = ifScopeDynamicAddMethodScope(object, attributes);\n+        return basedOnVoter.vote(authentication, object, dynamicConfigs);\n+    }\n+\n+    private Set<ConfigAttribute> ifScopeDynamicAddMethodScope(final Object object, final Collection<ConfigAttribute> attributes) {\n+        Set<ConfigAttribute> dynamicConfigs = new HashSet<>(attributes);\n+        if (object instanceof FilterInvocation && dynamicConfigs.remove(dynamic)) {\n+            addMethodScope(object, dynamicConfigs);\n+        }\n+        return dynamicConfigs;\n+    }\n+\n+    private void addMethodScope(final Object object, final Set<ConfigAttribute> dynamicConfigs) {\n+        final FilterInvocation f = (FilterInvocation) object;\n+        dynamicConfigs.add(new SecurityConfig("SCOPE_" + f.getRequest().getMethod().toUpperCase(Locale.ENGLISH)));\n+    }\n+}\n+\ndiff --git a/auth-server/src/main/java/org/osiam/security/authorization/OsiamUserApprovalHandler.java b/auth-server/src/main/java/org/osiam/security/authorization/OsiamUserApprovalHandler.java\nnew file mode 100644\nindex 00000000..f12e4da5\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/authorization/OsiamUserApprovalHandler.java\n@@ -0,0 +1,94 @@\n+package org.osiam.security.authorization;\n+\n+import org.springframework.security.core.Authentication;\n+import org.springframework.security.oauth2.provider.AuthorizationRequest;\n+import org.springframework.security.oauth2.provider.approval.DefaultUserApprovalHandler;\n+import org.springframework.stereotype.Component;\n+\n+import java.util.Date;\n+\n+/**\n+ * Osiam user approval handler extends the default user approval handler from spring.\n+ * It will add an implicit approval if configured in the client, so that the user is never asked to approve the client.\n+ * Additionally an expiry period can be configured if the implicit is not desired and the user need to approve once.\n+ * After that he will be asked again only if the period expires\n+ */\n+@Component("userApprovalHandler")\n+public class OsiamUserApprovalHandler extends DefaultUserApprovalHandler {\n+\n+    private static final int MILLISECONDS = 1000;\n+\n+    /**\n+     * Is called if OsiamUserApprovalHandler.isApproved() returns false and AccessConfirmation is done by the user.\n+     * Than it will save the approve date to be able to check it as long as user accepts approval.\n+     * So the user is not bothered every time to approve the client.\n+     *\n+     * @param authorizationRequest spring authorizationRequest\n+     * @param userAuthentication   spring userAuthentication\n+     * @return the authorizationRequest\n+     */\n+    @Override\n+    public AuthorizationRequest updateBeforeApproval(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {\n+        //check if "user_oauth_approval" is in the authorizationRequests approvalParameters and the (size != 0)\n+        // -> true for accessConfirmation -> save actual date\n+        if (authorizationRequest.getApprovalParameters().size() != 0 && authorizationRequest.getApprovalParameters().containsKey("user_oauth_approval")\n+                && authorizationRequest.getApprovalParameters().get("user_oauth_approval").equals("true")) {\n+            ClientEntity client = getClientDetails(authorizationRequest);\n+            Date date = new Date(System.currentTimeMillis() + (client.getValidityInSeconds() * MILLISECONDS));\n+            client.setExpiry(date);\n+\n+            //TODO: call /authentication/Client on resource server side\n+            //clientDao.update(client, authorizationRequest.getClientId());\n+        }\n+        return super.updateBeforeApproval(authorizationRequest, userAuthentication);\n+    }\n+\n+    /**\n+     * Checks if the client is configured to not ask the user for approval or if the date to ask again expires.\n+     *\n+     * @param authorizationRequest spring authorizationRequest\n+     * @param userAuthentication   spring userAuthentication\n+     * @return whether user approved the client or not\n+     */\n+    @Override\n+    public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {\n+        //check if implicit is configured in client or if user already confirmed approval once and validity time is not over\n+        ClientEntity client = getClientDetails(authorizationRequest);\n+        if (client.isImplicit()) {\n+            return true;\n+        } else if (client.getExpiry() != null && client.getExpiry().compareTo(new Date(System.currentTimeMillis())) >= 0) {\n+            return true;\n+        }\n+        return false;\n+    }\n+\n+    private ClientEntity getClientDetails(AuthorizationRequest authorizationRequest) {\n+        return new ClientEntity();\n+        //TODO: call /authentication/Client on resource server side\n+        //return clientDao.getClient(authorizationRequest.getClientId());\n+    }\n+\n+\n+    //TODO: remove this\n+    private class ClientEntity {\n+        private int validityInSeconds = 1000;\n+        private Date expiry = new Date();\n+        private boolean implicit = true;\n+\n+        public int getValidityInSeconds() {\n+            return validityInSeconds;\n+        }\n+\n+        public void setExpiry(Date expiry) {\n+            this.expiry = expiry;\n+        }\n+\n+        public Date getExpiry() {\n+            return expiry;\n+        }\n+\n+        public boolean isImplicit() {\n+            return implicit;\n+        }\n+    }\n+}\n\\ No newline at end of file\ndiff --git a/auth-server/src/main/java/org/osiam/security/authorization/package-info.java b/auth-server/src/main/java/org/osiam/security/authorization/package-info.java\nnew file mode 100644\nindex 00000000..96d13f5e\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/authorization/package-info.java\n@@ -0,0 +1,4 @@\n+/**\n+ * org.osiam.security.authorization is a group of classes which are needed by spring security for authorization purpose.\n+ */\n+package org.osiam.security.authorization;\n\\ No newline at end of file\ndiff --git a/auth-server/src/main/java/org/osiam/security/controller/AccessConfirmationController.java b/auth-server/src/main/java/org/osiam/security/controller/AccessConfirmationController.java\nnew file mode 100644\nindex 00000000..303b3110\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/controller/AccessConfirmationController.java\n@@ -0,0 +1,46 @@\n+package org.osiam.security.controller;\n+\n+import org.springframework.security.oauth2.provider.AuthorizationRequest;\n+import org.springframework.security.oauth2.provider.ClientDetails;\n+import org.springframework.security.oauth2.provider.ClientDetailsService;\n+import org.springframework.stereotype.Controller;\n+import org.springframework.web.bind.annotation.RequestMapping;\n+import org.springframework.web.bind.annotation.SessionAttributes;\n+import org.springframework.web.servlet.ModelAndView;\n+\n+import javax.inject.Inject;\n+import java.util.Map;\n+\n+/**\n+ * Controller for retrieving the model for and displaying the confirmation page for access to a protected resource.\n+ *\n+ * @author Ryan Heaton\n+ */\n+@Controller\n+@SessionAttributes("authorizationRequest")\n+public class AccessConfirmationController {\n+\n+    private ClientDetailsService clientDetailsService;\n+\n+    @RequestMapping("/oauth/confirm_access")\n+    public ModelAndView getAccessConfirmation(Map<String, Object> model) {\n+        AuthorizationRequest clientAuth = (AuthorizationRequest) model.remove("authorizationRequest");\n+        ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId()); // NOSONAR - clientDetailsService is initialized via setter injection\n+        model.put("auth_request", clientAuth);\n+        model.put("client", client);\n+        return new ModelAndView("access_confirmation", model);\n+    }\n+\n+    @RequestMapping("/oauth/error")\n+    public String handleError(Map<String, Object> model) {\n+        // We can add more stuff to the model here for JSP rendering. If the client was a machine then\n+        // the JSON will already have been rendered.\n+        model.put("message", "There was a problem with the OAuth2 protocol");\n+        return "oauth_error";\n+    }\n+\n+    @Inject\n+    public void setClientDetailsService(ClientDetailsService clientDetailsService) {\n+        this.clientDetailsService = clientDetailsService;\n+    }\n+}\ndiff --git a/auth-server/src/main/java/org/osiam/security/controller/FbTokenEndpoint.java b/auth-server/src/main/java/org/osiam/security/controller/FbTokenEndpoint.java\nnew file mode 100644\nindex 00000000..3f8b31ee\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/controller/FbTokenEndpoint.java\n@@ -0,0 +1,56 @@\n+package org.osiam.security.controller;\n+\n+import org.springframework.http.ResponseEntity;\n+import org.springframework.security.oauth2.common.OAuth2AccessToken;\n+import org.springframework.security.oauth2.provider.AuthorizationRequestManager;\n+import org.springframework.security.oauth2.provider.ClientDetailsService;\n+import org.springframework.security.oauth2.provider.TokenGranter;\n+import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;\n+import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;\n+import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;\n+import org.springframework.stereotype.Controller;\n+import org.springframework.web.bind.annotation.RequestMapping;\n+import org.springframework.web.bind.annotation.RequestParam;\n+import org.springframework.web.bind.annotation.ResponseBody;\n+\n+import javax.inject.Inject;\n+import java.security.Principal;\n+import java.util.Map;\n+\n+@Controller\n+/**\n+ * This is the endpoint for facebook connect. Instead of json Facebook uses key&value pairs:\n+ * "access_token=xxxx&expires=0000"\n+ * However the normal controller does deliver the access_token in json so we needed to create a second Controller for\n+ * that use case.\n+ *\n+ */\n+public class FbTokenEndpoint {\n+\n+    private WebResponseExceptionTranslator providerExceptionHandler = new DefaultWebResponseExceptionTranslator();\n+    @Inject\n+    private TokenGranter tokenGranter;\n+    @Inject\n+    private ClientDetailsService clientDetailsService;\n+    @Inject\n+    private AuthorizationRequestManager authorizationRequestManager;\n+\n+    private TokenEndpoint tokenEndpoint = new TokenEndpoint();\n+\n+    @RequestMapping(value = "/fb/oauth/access_token")\n+    @ResponseBody\n+    public String accessToken(Principal principal,\n+                              @RequestParam(value = "grant_type", defaultValue = "authorization_code")\n+                              String grantType, @RequestParam Map<String, String> parameters) {\n+\n+\n+        tokenEndpoint.setAuthorizationRequestManager(authorizationRequestManager);\n+        tokenEndpoint.setClientDetailsService(clientDetailsService);\n+        tokenEndpoint.setProviderExceptionHandler(providerExceptionHandler);\n+        tokenEndpoint.setTokenGranter(tokenGranter);\n+\n+        ResponseEntity<OAuth2AccessToken> accessToken = tokenEndpoint.getAccessToken(principal, grantType, parameters);\n+        return "access_token=" + accessToken.getBody().getValue() + "&expires=" + accessToken.getBody().getExpiresIn();\n+\n+    }\n+}\n\\ No newline at end of file\ndiff --git a/auth-server/src/main/java/org/osiam/security/controller/package-info.java b/auth-server/src/main/java/org/osiam/security/controller/package-info.java\nnew file mode 100644\nindex 00000000..3163de98\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/controller/package-info.java\n@@ -0,0 +1,5 @@\n+/**\n+ * org.osiam.security.controller is a group of classes which do generate the http api on deployment for security\n+ * related purposes.\n+ */\n+package org.osiam.security.controller;\n\\ No newline at end of file\ndiff --git a/auth-server/src/main/java/org/osiam/security/helper/FBClientCredentialsTokenEndpointFilter.java b/auth-server/src/main/java/org/osiam/security/helper/FBClientCredentialsTokenEndpointFilter.java\nnew file mode 100644\nindex 00000000..e6f01f11\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/helper/FBClientCredentialsTokenEndpointFilter.java\n@@ -0,0 +1,100 @@\n+package org.osiam.security.helper;\n+\n+import org.springframework.security.authentication.BadCredentialsException;\n+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\n+import org.springframework.security.core.Authentication;\n+import org.springframework.security.core.AuthenticationException;\n+import org.springframework.security.oauth2.common.exceptions.BadClientCredentialsException;\n+import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;\n+import org.springframework.security.web.AuthenticationEntryPoint;\n+import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;\n+import org.springframework.security.web.authentication.AuthenticationFailureHandler;\n+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;\n+\n+import javax.servlet.FilterChain;\n+import javax.servlet.ServletException;\n+import javax.servlet.http.HttpServletRequest;\n+import javax.servlet.http.HttpServletResponse;\n+import java.io.IOException;\n+\n+/**\n+ * This filter is basically just a fork of ClientCredentialsTokenEndpointFilter apparently they have only one constructor\n+ * which shows to the wrong url in our case (oauth/token) we need two endpoint:\n+ * the first on is for oauth2 in general: oauth/token\n+ * the second one if for facebook: /fb/oauth/access_token\n+ * Since facebook does not enforce http basic we don\'t do it either, therefore we need a filter\n+ * to authenticate a client via send parameter (clientid, client_secret).\n+ */\n+public class FBClientCredentialsTokenEndpointFilter extends AbstractAuthenticationProcessingFilter {\n+\n+    private AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();\n+\n+\n+    protected FBClientCredentialsTokenEndpointFilter() {\n+        super("/fb/oauth/access_token");\n+    }\n+\n+    @Override\n+    /**\n+     * Sets the handler, failed -> BadCredentialsException, success -> just continue.\n+     */\n+    public void afterPropertiesSet() {\n+        super.afterPropertiesSet();\n+        setAuthenticationFailureHandler(new AuthenticationFailureHandler() {\n+            public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,\n+                                                AuthenticationException exception)\n+                    throws IOException, ServletException {\n+                if (exception instanceof BadCredentialsException) {\n+                    exception = // NOSONAR\n+                            new BadCredentialsException(exception.getMessage(), new BadClientCredentialsException());\n+                }\n+                authenticationEntryPoint.commence(request, response, exception);\n+            }\n+        });\n+        setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());\n+    }\n+\n+    private static class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {\n+        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,\n+                                            Authentication authentication) throws IOException, ServletException {\n+            // no-op - just allow filter chain to continue to token endpoint\n+        }\n+    }\n+\n+    @Override\n+    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)\n+            throws IOException, ServletException {\n+        String clientId = request.getParameter("client_id");\n+        String clientSecret = request.getParameter("client_secret");\n+        if (clientId == null) {\n+            return null;\n+        }\n+        if (clientSecret == null) {\n+            clientSecret = "";\n+        }\n+        clientId = clientId.trim();\n+        UsernamePasswordAuthenticationToken authRequest =\n+                new UsernamePasswordAuthenticationToken(clientId, clientSecret);\n+        return this.getAuthenticationManager().authenticate(authRequest);\n+\n+    }\n+\n+    @Override\n+    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,\n+                                            Authentication authResult) throws IOException, ServletException {\n+        super.successfulAuthentication(request, response, chain, authResult);\n+        chain.doFilter(request, response);\n+    }\n+\n+    @Override\n+    protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {\n+        String clientId = request.getParameter("client_id");\n+        if (clientId == null) {\n+            // Give basic auth a chance to work instead (it\'s preferred anyway)\n+            return false;\n+        }\n+\n+        return super.requiresAuthentication(request, response);\n+    }\n+}\n+\ndiff --git a/auth-server/src/main/java/org/osiam/security/helper/LessStrictRedirectUriAuthorizationCodeTokenGranter.java b/auth-server/src/main/java/org/osiam/security/helper/LessStrictRedirectUriAuthorizationCodeTokenGranter.java\nnew file mode 100644\nindex 00000000..adacb7f1\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/helper/LessStrictRedirectUriAuthorizationCodeTokenGranter.java\n@@ -0,0 +1,105 @@\n+package org.osiam.security.helper;\n+\n+import org.springframework.security.core.Authentication;\n+import org.springframework.security.oauth2.common.exceptions.InvalidClientException;\n+import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;\n+import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;\n+import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException;\n+import org.springframework.security.oauth2.provider.AuthorizationRequest;\n+import org.springframework.security.oauth2.provider.ClientDetailsService;\n+import org.springframework.security.oauth2.provider.DefaultAuthorizationRequest;\n+import org.springframework.security.oauth2.provider.OAuth2Authentication;\n+import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;\n+import org.springframework.security.oauth2.provider.code.AuthorizationRequestHolder;\n+import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;\n+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;\n+\n+import javax.inject.Inject;\n+import java.util.HashMap;\n+import java.util.Map;\n+\n+/**\n+ * This class is a fork of  AuthorizationCodeTokenGranter the only difference is that we want to check if the pending\n+ * redirect uri startsWith the send redirect uri.\n+ * <p/>\n+ * The reason for this is that some connector do build different redirect uris when getting an authorization_code\n+ * (like Liferay) and send a simpler redirect uri when getting the access_token (because it doesn\'t matter on\n+ * exchanging the auth_code with an access_token)\n+ */\n+public class LessStrictRedirectUriAuthorizationCodeTokenGranter extends AbstractTokenGranter {\n+\n+\n+    private static final String GRANT_TYPE = "authorization_code";\n+    @Inject\n+    private AuthorizationCodeServices authorizationCodeServices;\n+\n+    public LessStrictRedirectUriAuthorizationCodeTokenGranter(AuthorizationServerTokenServices tokenServices,\n+                                                              ClientDetailsService clientDetailsService) {\n+        super(tokenServices, clientDetailsService, GRANT_TYPE);\n+    }\n+\n+    @Override\n+    protected OAuth2Authentication getOAuth2Authentication(AuthorizationRequest authorizationRequest) {\n+\n+        Map<String, String> parameters = authorizationRequest.getAuthorizationParameters();\n+        AuthorizationRequestHolder storedAuth = getAuthorizationRequestHolder(parameters);\n+        String redirectUri = parameters.get(AuthorizationRequest.REDIRECT_URI);\n+\n+        AuthorizationRequest pendingAuthorizationRequest = storedAuth.getAuthenticationRequest();\n+        validateRedirectUri(redirectUri, pendingAuthorizationRequest);\n+        validateClientId(authorizationRequest, pendingAuthorizationRequest);\n+\n+        // Secret is not required in the authorization request, so it won\'t be available\n+        // in the pendingAuthorizationRequest. We do want to check that a secret is provided\n+        // in the token request, but that happens elsewhere.\n+        Map<String, String> combinedParameters =\n+                new HashMap<String, String>(storedAuth.getAuthenticationRequest().getAuthorizationParameters());\n+        // Combine the parameters adding the new ones last so they override if there are any clashes\n+        combinedParameters.putAll(parameters);\n+        // Similarly scopes are not required in the token request, so we don\'t make a comparison here, just\n+        // enforce validity through the AuthorizationRequestFactory.\n+        DefaultAuthorizationRequest outgoingRequest = new DefaultAuthorizationRequest(pendingAuthorizationRequest);\n+        outgoingRequest.setAuthorizationParameters(combinedParameters);\n+\n+        Authentication userAuth = storedAuth.getUserAuthentication();\n+        return new OAuth2Authentication(outgoingRequest, userAuth);\n+\n+    }\n+\n+    private void validateClientId(AuthorizationRequest authorizationRequest,\n+                                  AuthorizationRequest pendingAuthorizationRequest) {\n+        String pendingClientId = pendingAuthorizationRequest.getClientId();\n+        String clientId = authorizationRequest.getClientId();\n+        if (clientId != null && !clientId.equals(pendingClientId)) {\n+            // just a sanity check.\n+            throw new InvalidClientException("Client ID mismatch");\n+        }\n+    }\n+\n+    private void validateRedirectUri(String redirectUri, AuthorizationRequest pendingAuthorizationRequest) {\n+        // https://jira.springsource.org/browse/SECOAUTH-333\n+        // This might be null, if the authorization was done without the redirect_uri parameter\n+        String redirectUriApprovalParameter =\n+                pendingAuthorizationRequest.getAuthorizationParameters().get(AuthorizationRequest.REDIRECT_URI);\n+\n+        String uri = pendingAuthorizationRequest.getRedirectUri();\n+\n+        if ((redirectUriApprovalParameter != null && redirectUri == null) ||\n+                (redirectUriApprovalParameter != null && (!uri.startsWith(redirectUri)))) {\n+            throw new RedirectMismatchException("Redirect URI mismatch.");\n+        }\n+    }\n+\n+    private AuthorizationRequestHolder getAuthorizationRequestHolder(Map<String, String> parameters) {\n+        String authorizationCode = parameters.get("code");\n+        if (authorizationCode == null) {\n+            throw new OAuth2Exception("An authorization code must be supplied.");\n+        }\n+\n+        AuthorizationRequestHolder storedAuth = authorizationCodeServices.consumeAuthorizationCode(authorizationCode);\n+        if (storedAuth == null) {\n+            throw new InvalidGrantException("Invalid authorization code: " + authorizationCode);\n+        }\n+        return storedAuth;\n+    }\n+}\ndiff --git a/auth-server/src/main/java/org/osiam/security/helper/package-info.java b/auth-server/src/main/java/org/osiam/security/helper/package-info.java\nnew file mode 100644\nindex 00000000..e814c030\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/helper/package-info.java\n@@ -0,0 +1,4 @@\n+/**\n+ * org.osiam.security.helper is a group of classes which are helping to handle the security related logic.\n+ */\n+package org.osiam.security.helper;\n\\ No newline at end of file\ndiff --git a/auth-server/src/main/java/org/osiam/security/package-info.java b/auth-server/src/main/java/org/osiam/security/package-info.java\nnew file mode 100644\nindex 00000000..fe1e5ec1\n--- /dev/null\n+++ b/auth-server/src/main/java/org/osiam/security/package-info.java\n@@ -0,0 +1,27 @@\n+/**\n+ * <p>org.osiam.security is a group of groups with the focus on security.\n+ *\n+ * In OSIAM authentication and authorization are done by Spring-Security, there are some modification.\n+ *\n+ * OSIAM does use the OAuth2 authorization-code flow protocol delivered by spring-security-oauth2 and has a own facebook connect like implementation\n+ * to be able to federate an existing OSIAM user to an other system by calling /me with an email scope.\n+ *\n+ * Spring Username Password authentication does use the SHA-512 algorithm the hash the passwords of an user and the\n+ * internal id for salting it.</p>\n+ *\n+ * <p>To be able to get and authorization code you need to redirect an user of your client to:</p>\n+ *\n+ * <p>/oauth/authorize?client_id=CLIENT_ID&response_type=code</p>\n+ *\n+ * <p>and the excahnge the delivered auth-code to an access_token you need to call either:</p>\n+ *\n+ * <p>/osiam-server/oauth/token</p>\n+ *\n+ * <p>for the general json access_token or:</p>\n+ *\n+ * <p>/osiam-server/fb/oauth/access_token</p>\n+ *\n+ * <p>for the facebook like key value pairs.</p>\n+ *\n+ */\n+package org.osiam.security;\n\\ No newline at end of file\ndiff --git a/auth-server/src/main/webapp/WEB-INF/client-authentication.xml b/auth-server/src/main/webapp/WEB-INF/client-authentication.xml\nnew file mode 100644\nindex 00000000..1251b970\n--- /dev/null\n+++ b/auth-server/src/main/webapp/WEB-INF/client-authentication.xml\n@@ -0,0 +1,95 @@\n+<?xml version="1.0" encoding="UTF-8" ?>\n+<!--\n+  ~ Copyright (C) 2013 tarent AG\n+  ~\n+  ~ Permission is hereby granted, free of charge, to any person obtaining\n+  ~ a copy of this software and associated documentation files (the\n+  ~ "Software"), to deal in the Software without restriction, including\n+  ~ without limitation the rights to use, copy, modify, merge, publish,\n+  ~ distribute, sublicense, and/or sell copies of the Software, and to\n+  ~ permit persons to whom the Software is furnished to do so, subject to\n+  ~ the following conditions:\n+  ~\n+  ~ The above copyright notice and this permission notice shall be\n+  ~ included in all copies or substantial portions of the Software.\n+  ~\n+  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+  ~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+  ~ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+  ~ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+  ~ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+  ~ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+  ~ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+  -->\n+\n+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n+       xmlns:oauth="http://www.springframework.org/schema/security/oauth2"\n+       xmlns:sec="http://www.springframework.org/schema/security"\n+       xmlns:mvc="http://www.springframework.org/schema/mvc"\n+       xmlns:context="http://www.springframework.org/schema/context"\n+       xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd\n+        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd\n+        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd\n+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd\n+        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">\n+\n+    <!-- OAuth2 Access Token interface this is used by clients to request an access token for a certain resource -->\n+    <http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"\n+          xmlns="http://www.springframework.org/schema/security">\n+\n+        <!-- the client needs to authenticate itself -->\n+        <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />\n+        <anonymous enabled="false" />\n+\n+        <!-- use http basic with this entry point authentication method to authenticate the client -->\n+        <http-basic entry-point-ref="clientAuthenticationEntryPoint" />\n+\n+        <!-- include this only if you need to authenticate clients via request parameters -->\n+        <custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />\n+\n+        <!-- uses general oauthAccessDeniedHandler -->\n+        <access-denied-handler ref="oauthAccessDeniedHandler" />\n+    </http>\n+\n+    <http pattern="/fb/oauth/access_token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"\n+          xmlns="http://www.springframework.org/schema/security">\n+\n+        <!-- the client needs to authenticate itself -->\n+        <intercept-url pattern="/fb/oauth/access_token" access="IS_AUTHENTICATED_FULLY" />\n+        <anonymous enabled="false" />\n+\n+        <!-- use http basic with this entry point authentication method to authenticate the client -->\n+        <http-basic entry-point-ref="clientAuthenticationEntryPoint" />\n+\n+        <!-- include this only if you need to authenticate clients via request parameters -->\n+        <custom-filter ref="fbClientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />\n+\n+        <!-- uses general oauthAccessDeniedHandler -->\n+        <access-denied-handler ref="oauthAccessDeniedHandler" />\n+    </http>\n+\n+    <bean id="fbClientCredentialsTokenEndpointFilter" class="org.osiam.security.helper.FBClientCredentialsTokenEndpointFilter">\n+        <property name="authenticationManager" ref="clientAuthenticationManager" />\n+    </bean>\n+\n+\n+    <bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">\n+        <property name="authenticationManager" ref="clientAuthenticationManager" />\n+    </bean>\n+\n+    <!-- client authentication manager -->\n+    <authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">\n+        <authentication-provider user-service-ref="clientDetailsUserService" />\n+    </authentication-manager>\n+\n+    <!-- service holding client data -->\n+    <bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">\n+        <constructor-arg ref="clientDetails" />\n+    </bean>\n+\n+    <!-- the OAuth2 authentication entry point -->\n+    <bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">\n+        <property name="realmName" value="authorization-server/client" />\n+    </bean>\n+\n+</beans>\ndiff --git a/auth-server/src/main/webapp/WEB-INF/jsp/access_confirmation.jsp b/auth-server/src/main/webapp/WEB-INF/jsp/access_confirmation.jsp\nnew file mode 100644\nindex 00000000..3d32fa67\n--- /dev/null\n+++ b/auth-server/src/main/webapp/WEB-INF/jsp/access_confirmation.jsp\n@@ -0,0 +1,69 @@\n+<%@ page import="org.springframework.security.core.AuthenticationException" %>\n+<%@ page import="org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter" %>\n+<%@ page import="org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException" %>\n+<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>\n+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>\n+<%--\n+  ~ Copyright (C) 2013 tarent AG\n+  ~\n+  ~ Permission is hereby granted, free of charge, to any person obtaining\n+  ~ a copy of this software and associated documentation files (the\n+  ~ "Software"), to deal in the Software without restriction, including\n+  ~ without limitation the rights to use, copy, modify, merge, publish,\n+  ~ distribute, sublicense, and/or sell copies of the Software, and to\n+  ~ permit persons to whom the Software is furnished to do so, subject to\n+  ~ the following conditions:\n+  ~\n+  ~ The above copyright notice and this permission notice shall be\n+  ~ included in all copies or substantial portions of the Software.\n+  ~\n+  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+  ~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+  ~ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+  ~ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+  ~ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+  ~ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+  ~ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+  --%>\n+\n+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n+<html xmlns="http://www.w3.org/1999/xhtml">\n+<head>\n+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>\n+  <title>Auth-Server</title>\n+  <link type="text/css" rel="stylesheet" href="<c:url value="/style.css"/>"/>\n+</head>\n+\n+<body>\n+\n+  <h1>Demo</h1>\n+\n+  <div id="content">\n+\n+    <% if (session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY) != null && !(session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY) instanceof UnapprovedClientAuthenticationException)) { %>\n+      <div class="error">\n+        <h2>Woops!</h2>\n+\n+        <p>Access could not be granted. (<%= ((AuthenticationException) session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>)</p>\n+      </div>\n+    <% } %>\n+    <c:remove scope="session" var="SPRING_SECURITY_LAST_EXCEPTION"/>\n+\n+    <authz:authorize ifAllGranted="ROLE_USER">\n+      <h2>Please Confirm</h2>\n+\n+      <p>You hereby authorize "<c:out value="${client.clientId}"/>" to access your protected resources.</p>\n+\n+      <form id="confirmationForm" name="confirmationForm" action="<%=request.getContextPath()%>/oauth/authorize" method="post">\n+        <input name="user_oauth_approval" value="true" type="hidden"/>\n+        <label><input name="authorize" value="Authorize" type="submit"></label>\n+      </form>\n+      <form id="denialForm" name="denialForm" action="<%=request.getContextPath()%>/oauth/authorize" method="post">\n+        <input name="user_oauth_approval" value="false" type="hidden"/>\n+        <label><input name="deny" value="Deny" type="submit"></label>\n+      </form>\n+    </authz:authorize>\n+  </div>\n+\n+</body>\n+</html>\ndiff --git a/auth-server/src/main/webapp/WEB-INF/jsp/oauth_error.jsp b/auth-server/src/main/webapp/WEB-INF/jsp/oauth_error.jsp\nnew file mode 100644\nindex 00000000..3789caff\n--- /dev/null\n+++ b/auth-server/src/main/webapp/WEB-INF/jsp/oauth_error.jsp\n@@ -0,0 +1,43 @@\n+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>\n+<%--\n+  ~ Copyright (C) 2013 tarent AG\n+  ~\n+  ~ Permission is hereby granted, free of charge, to any person obtaining\n+  ~ a copy of this software and associated documentation files (the\n+  ~ "Software"), to deal in the Software without restriction, including\n+  ~ without limitation the rights to use, copy, modify, merge, publish,\n+  ~ distribute, sublicense, and/or sell copies of the Software, and to\n+  ~ permit persons to whom the Software is furnished to do so, subject to\n+  ~ the following conditions:\n+  ~\n+  ~ The above copyright notice and this permission notice shall be\n+  ~ included in all copies or substantial portions of the Software.\n+  ~\n+  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+  ~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+  ~ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+  ~ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+  ~ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+  ~ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+  ~ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+  --%>\n+\n+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n+<html xmlns="http://www.w3.org/1999/xhtml">\n+<head>\n+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>\n+  <title>Auth-Server</title>\n+  <link type="text/css" rel="stylesheet" href="<c:url value="/style.css"/>"/>\n+</head>\n+\n+<body>\n+\n+  <h1>Auth-Server OAuth2 Error</h1>\n+\n+  <div id="content">\n+\t<p><c:out value="${message}"/> (<c:out value="${error.summary}"/>)</p>\n+\t<p>Please go back to your client application and try again, or contact the owner and ask for support</p>\n+  </div>\n+\n+</body>\n+</html>\ndiff --git a/auth-server/src/main/webapp/WEB-INF/spring-servlet.xml b/auth-server/src/main/webapp/WEB-INF/spring-servlet.xml\nnew file mode 100644\nindex 00000000..bd9e0807\n--- /dev/null\n+++ b/auth-server/src/main/webapp/WEB-INF/spring-servlet.xml\n@@ -0,0 +1,130 @@\n+<?xml version="1.0" encoding="UTF-8" ?>\n+<!--\n+  ~ Copyright (C) 2013 tarent AG\n+  ~\n+  ~ Permission is hereby granted, free of charge, to any person obtaining\n+  ~ a copy of this software and associated documentation files (the\n+  ~ "Software"), to deal in the Software without restriction, including\n+  ~ without limitation the rights to use, copy, modify, merge, publish,\n+  ~ distribute, sublicense, and/or sell copies of the Software, and to\n+  ~ permit persons to whom the Software is furnished to do so, subject to\n+  ~ the following conditions:\n+  ~\n+  ~ The above copyright notice and this permission notice shall be\n+  ~ included in all copies or substantial portions of the Software.\n+  ~\n+  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+  ~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+  ~ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+  ~ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+  ~ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+  ~ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+  ~ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+  -->\n+\n+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n+       xmlns:oauth="http://www.springframework.org/schema/security/oauth2"\n+       xmlns:sec="http://www.springframework.org/schema/security"\n+       xmlns:mvc="http://www.springframework.org/schema/mvc"\n+       xmlns:context="http://www.springframework.org/schema/context"\n+       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"\n+       xmlns:beans="http://www.springframework.org/schema/beans"\n+       xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd\n+        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd\n+        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd\n+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd\n+        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd\n+        http://www.springframework.org/schema/aop\n+        http://www.springframework.org/schema/aop/spring-aop-3.1.xsd\n+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n+        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">\n+\n+\n+\n+    <!-- needed for exchanging the authorization_code to an access_token -->\n+    <import resource="client-authentication.xml"/>\n+    <!-- needed for getting an authorization-code -->\n+    <import resource="user-authentication.xml"/>\n+\n+\n+    <!-- configures the OAuth2 authorization server -->\n+    <oauth:authorization-server client-details-service-ref="clientDetails"\n+                                token-services-ref="tokenServices"\n+                                token-granter-ref="customCompositeTokenGranter"\n+                                user-approval-handler-ref="userApprovalHandler">\n+        <oauth:authorization-code/>\n+        <oauth:refresh-token/>\n+        <oauth:client-credentials/>\n+        <oauth:password/>\n+    </oauth:authorization-server>\n+\n+    <beans:bean id="customCompositeTokenGranter"\n+                class="org.springframework.security.oauth2.provider.CompositeTokenGranter">\n+        <beans:constructor-arg>\n+            <util:list>\n+                <beans:bean class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter">\n+                    <constructor-arg ref="tokenServices"/>\n+                    <constructor-arg ref="clientDetails"/>\n+                </beans:bean>\n+                <beans:bean class="org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter">\n+                    <constructor-arg ref="authenticationManager"/>\n+                    <constructor-arg ref="tokenServices"/>\n+                    <constructor-arg ref="clientDetails"/>\n+                </beans:bean>\n+                <beans:bean class="org.springframework.security.oauth2.provider.refresh.RefreshTokenGranter">\n+                    <constructor-arg ref="tokenServices"/>\n+                    <constructor-arg ref="clientDetails"/>\n+                </beans:bean>\n+                <beans:bean class="org.osiam.security.helper.LessStrictRedirectUriAuthorizationCodeTokenGranter">\n+                    <constructor-arg ref="tokenServices"/>\n+                    <constructor-arg ref="clientDetails"/>\n+                </beans:bean>\n+            </util:list>\n+        </beans:constructor-arg>\n+    </beans:bean>\n+\n+    <!-- access token services -->\n+    <bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">\n+        <property name="tokenStore" ref="tokenStore"/>\n+        <property name="supportRefreshToken" value="true"/>\n+        <property name="clientDetailsService" ref="clientDetails"/>\n+    </bean>\n+\n+    <!-- the token storage managing all access tokens -->\n+    <bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore"/>\n+\n+    <!-- Enabled @Secured annotation -->\n+    <sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">\n+        <!--you could also wire in the expression handler up at the layer of the http filters. See https://jira.springsource.org/browse/SEC-1452 -->\n+        <sec:expression-handler ref="oauthExpressionHandler"/>\n+    </sec:global-method-security>\n+\n+    <!-- handles denied accesses of @secured methods -->\n+    <oauth:expression-handler id="oauthExpressionHandler"/>\n+\n+    <!-- view resolver to find JSP\'s -->\n+    <bean id="viewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">\n+        <property name="viewResolvers">\n+            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">\n+                <property name="prefix" value="/WEB-INF/jsp/"/>\n+                <property name="suffix" value=".jsp"/>\n+            </bean>\n+        </property>\n+        <property name="defaultViews">\n+            <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">\n+                <property name="extractValueFromSingleKeyModel" value="true"/>\n+            </bean>\n+        </property>\n+    </bean>\n+\n+    <!-- general access denied handler -->\n+    <bean id="oauthAccessDeniedHandler"\n+          class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>\n+\n+    <mvc:annotation-driven/>\n+\n+    <mvc:default-servlet-handler/>\n+\n+    <context:component-scan base-package="org.osiam"/>\n+    <context:annotation-config/>\n+</beans>\ndiff --git a/auth-server/src/main/webapp/WEB-INF/user-authentication.xml b/auth-server/src/main/webapp/WEB-INF/user-authentication.xml\nnew file mode 100644\nindex 00000000..e728ca2a\n--- /dev/null\n+++ b/auth-server/src/main/webapp/WEB-INF/user-authentication.xml\n@@ -0,0 +1,71 @@\n+<?xml version="1.0" encoding="UTF-8" ?>\n+<!--\n+  ~ Copyright (C) 2013 tarent AG\n+  ~\n+  ~ Permission is hereby granted, free of charge, to any person obtaining\n+  ~ a copy of this software and associated documentation files (the\n+  ~ "Software"), to deal in the Software without restriction, including\n+  ~ without limitation the rights to use, copy, modify, merge, publish,\n+  ~ distribute, sublicense, and/or sell copies of the Software, and to\n+  ~ permit persons to whom the Software is furnished to do so, subject to\n+  ~ the following conditions:\n+  ~\n+  ~ The above copyright notice and this permission notice shall be\n+  ~ included in all copies or substantial portions of the Software.\n+  ~\n+  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+  ~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+  ~ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+  ~ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+  ~ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+  ~ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+  ~ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+  -->\n+\n+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n+       xmlns:oauth="http://www.springframework.org/schema/security/oauth2"\n+       xmlns:sec="http://www.springframework.org/schema/security"\n+       xmlns:mvc="http://www.springframework.org/schema/mvc"\n+       xmlns:context="http://www.springframework.org/schema/context"\n+       xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd\n+        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd\n+        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd\n+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd\n+        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">\n+\n+\n+    <!-- OAuth2 User Login/Grant Access interface provides a login form for the user to login and grant access of resources\n+        to a client -->\n+    <http access-denied-page="/login.jsp?authorization_error=true" disable-url-rewriting="true"\n+          xmlns="http://www.springframework.org/schema/security">\n+        <!-- generally all resources below /oauth are accessed as role "USER" this does not affect more specialized configurations -->\n+        <intercept-url pattern="/oauth/**" access="ROLE_USER"/>\n+        <!-- shows a login form to the user -->\n+        <form-login authentication-failure-url="/login.jsp?authentication_error=true" login-page="/login.jsp"\n+                    login-processing-url="/login.do"/>\n+        <!-- this needs to be accessible anonymously -->\n+        <anonymous enabled="true"/>\n+    </http>\n+\n+\n+    <authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">\n+\n+        <authentication-provider user-service-ref="userDetailsService">\n+            <password-encoder ref="passwordEncoder">\n+                <salt-source ref="saltSource"/>\n+            </password-encoder>\n+        </authentication-provider>\n+    </authentication-manager>\n+\n+    <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">\n+        <constructor-arg value="512"/>\n+        <property name="iterations" value="1000"/>\n+    </bean>\n+\n+\n+    <bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource">\n+        <property name="userPropertyToUse" value="id"/>\n+    </bean>\n+\n+\n+</beans>\ndiff --git a/auth-server/src/main/webapp/WEB-INF/web.xml b/auth-server/src/main/webapp/WEB-INF/web.xml\nindex f159f9a4..ab4446e8 100644\n--- a/auth-server/src/main/webapp/WEB-INF/web.xml\n+++ b/auth-server/src/main/webapp/WEB-INF/web.xml\n@@ -26,4 +26,18 @@\n          xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"\n          version="3.0">\n \n+    <filter>\n+        <filter-name>springSecurityFilterChain</filter-name>\n+        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>\n+        <init-param>\n+            <param-name>contextAttribute</param-name>\n+            <param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>\n+        </init-param>\n+    </filter>\n+\n+    <filter-mapping>\n+        <filter-name>springSecurityFilterChain</filter-name>\n+        <url-pattern>/*</url-pattern>\n+    </filter-mapping>\n+\n </web-app>\n\\ No newline at end of file\ndiff --git a/auth-server/src/main/webapp/login.jsp b/auth-server/src/main/webapp/login.jsp\nnew file mode 100644\nindex 00000000..df9ec8ef\n--- /dev/null\n+++ b/auth-server/src/main/webapp/login.jsp\n@@ -0,0 +1,70 @@\n+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>\n+\n+<%--\n+  ~ Copyright (C) 2013 tarent AG\n+  ~\n+  ~ Permission is hereby granted, free of charge, to any person obtaining\n+  ~ a copy of this software and associated documentation files (the\n+  ~ "Software"), to deal in the Software without restriction, including\n+  ~ without limitation the rights to use, copy, modify, merge, publish,\n+  ~ distribute, sublicense, and/or sell copies of the Software, and to\n+  ~ permit persons to whom the Software is furnished to do so, subject to\n+  ~ the following conditions:\n+  ~\n+  ~ The above copyright notice and this permission notice shall be\n+  ~ included in all copies or substantial portions of the Software.\n+  ~\n+  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+  ~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+  ~ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+  ~ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+  ~ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+  ~ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+  ~ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+  --%>\n+\n+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n+<html xmlns="http://www.w3.org/1999/xhtml">\n+<head>\n+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />\n+<title>Auth-Server</title>\n+<link type="text/css" rel="stylesheet"\n+\thref="<c:url value="/style.css"/>" />\n+</head>\n+\n+<body>\n+\n+\t<h1>Auth-Server</h1>\n+\n+\t<div id="content">\n+\t\t<c:if test="${not empty param.authentication_error}">\n+\t\t\t<h1>Woops!</h1>\n+\n+\t\t\t<p class="error">Your login attempt was not successful.</p>\n+\t\t</c:if>\n+\t\t<c:if test="${not empty param.authorization_error}">\n+\t\t\t<h1>Woops!</h1>\n+\n+\t\t\t<p class="error">You are not permitted to access that resource.</p>\n+\t\t</c:if>\n+\n+\t\t<h2>Login</h2>\n+\n+\t\t<p>We\'ve got 1 user: marissa. Go ahead and log in. Marissa\'s password is "koala".</p>\n+\t\t<form id="loginForm" name="loginForm"\n+\t\t\taction="<c:url value="/login.do"/>" method="post">\n+\t\t\t<p>\n+\t\t\t\t<label>Username: <input type=\'text\' name=\'j_username\' value="marissa" /></label>\n+\t\t\t</p>\n+\t\t\t<p>\n+\t\t\t\t<label>Password: <input type=\'text\' name=\'j_password\' value="koala" /></label>\n+\t\t\t</p>\n+\n+\t\t\t<p>\n+\t\t\t\t<input name="login" value="Login" type="submit"/>\n+\t\t\t</p>\n+\t\t</form>\n+\t</div>\n+\n+</body>\n+</html>\ndiff --git a/auth-server/src/main/webapp/style.css b/auth-server/src/main/webapp/style.css\nnew file mode 100644\nindex 00000000..291ba734\n--- /dev/null\n+++ b/auth-server/src/main/webapp/style.css\n@@ -0,0 +1,79 @@\n+/*\n+ * Copyright (C) 2013 tarent AG\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining\n+ * a copy of this software and associated documentation files (the\n+ * "Software"), to deal in the Software without restriction, including\n+ * without limitation the rights to use, copy, modify, merge, publish,\n+ * distribute, sublicense, and/or sell copies of the Software, and to\n+ * permit persons to whom the Software is furnished to do so, subject to\n+ * the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be\n+ * included in all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+ */\n+\n+/* CSS Document */\n+\n+body {\n+  color: white;\n+  font-family: \'Trebuchet MS\', Helvetica, sans-serif;\n+  font-size: 12px;\n+  margin: 0 auto;\n+  width: 736px;\n+}\n+\n+#content {\n+  background: #3d3d3d;\n+  width: 676px;\n+  margin-top: 20px;\n+  padding: 0 30px 25px 30px;\n+}\n+\n+h1 {\n+  height: 36px;\n+  width: 721px;\n+  margin: 0 0 1em 0;\n+  padding-top: 80px;\n+  padding-left: 15px;\n+  font-size: 1.8em;\n+  font-variant: small-caps;\n+}\n+\n+h2 {\n+  font-size: 1.2em;\n+  margin-left: -10px;\n+  padding-top: 20px;\n+  font-weight: bold;\n+  letter-spacing: .3px;\n+}\n+\n+.error h2 {\n+  color: red;\n+  font-size: 1.2em;\n+  padding-top: 20px;\n+  font-weight: bold;\n+  letter-spacing: .3px;\n+}\n+\n+.error p {\n+  color: red;\n+}\n+\n+p {\n+  letter-spacing: .2px;\n+}\n+\n+label {\n+  text-indent: 20px;\n+  letter-spacing: .2px;\n+  padding: 5px 5px 5px 5px;\n+}\ndiff --git a/auth-server/src/test/groovy/org/osiam/security/authentication/AuthenticationBeanTest.groovy b/auth-server/src/test/groovy/org/osiam/security/authentication/AuthenticationBeanTest.groovy\nnew file mode 100644\nindex 00000000..9a776fe0\n--- /dev/null\n+++ b/auth-server/src/test/groovy/org/osiam/security/authentication/AuthenticationBeanTest.groovy\n@@ -0,0 +1,46 @@\n+/*\n+ * Copyright (C) 2013 tarent AG\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining\n+ * a copy of this software and associated documentation files (the\n+ * "Software"), to deal in the Software without restriction, including\n+ * without limitation the rights to use, copy, modify, merge, publish,\n+ * distribute, sublicense, and/or sell copies of the Software, and to\n+ * permit persons to whom the Software is furnished to do so, subject to\n+ * the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be\n+ * included in all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+ */\n+\n+package org.osiam.security.authentication\n+\n+import org.osiam.storage.dao.UserDAO\n+import org.osiam.storage.entities.UserEntity\n+import spock.lang.Specification\n+\n+class AuthenticationBeanTest extends Specification {\n+    def userDao = Mock(UserDAO)\n+    def underTest = new AuthenticationBean(userDAO: userDao)\n+\n+    def "should return an user found by userdao"() {\n+        given:\n+        def user = Mock(UserEntity)\n+        when:\n+        def result = underTest.loadUserByUsername("hui")\n+        then:\n+        1 * userDao.getByUsername("hui") >> user\n+        result == user\n+\n+    }\n+\n+\n+}\ndiff --git a/auth-server/src/test/groovy/org/osiam/security/authentication/ClientDetailsLoadingBeanTest.groovy b/auth-server/src/test/groovy/org/osiam/security/authentication/ClientDetailsLoadingBeanTest.groovy\nnew file mode 100644\nindex 00000000..2aed2aa1\n--- /dev/null\n+++ b/auth-server/src/test/groovy/org/osiam/security/authentication/ClientDetailsLoadingBeanTest.groovy\n@@ -0,0 +1,41 @@\n+/*\n+ * Copyright (C) 2013 tarent AG\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining\n+ * a copy of this software and associated documentation files (the\n+ * "Software"), to deal in the Software without restriction, including\n+ * without limitation the rights to use, copy, modify, merge, publish,\n+ * distribute, sublicense, and/or sell copies of the Software, and to\n+ * permit persons to whom the Software is furnished to do so, subject to\n+ * the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be\n+ * included in all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+ */\n+\n+package org.osiam.security.authentication\n+\n+import org.osiam.storage.dao.ClientDao\n+import spock.lang.Specification\n+\n+class ClientDetailsLoadingBeanTest extends Specification {\n+\n+    def clientDaoMock = Mock(ClientDao)\n+    def underTest = new ClientDetailsLoadingBean(clientDao: clientDaoMock)\n+\n+    def "should return a client"(){\n+        when:\n+        underTest.loadClientByClientId("hanz")\n+\n+        then:\n+        1 * clientDaoMock.getClient("hanz")\n+    }\n+}\n\\ No newline at end of file\ndiff --git a/auth-server/src/test/groovy/org/osiam/security/authorization/OsiamUserApprovalHandlerTest.groovy b/auth-server/src/test/groovy/org/osiam/security/authorization/OsiamUserApprovalHandlerTest.groovy\nnew file mode 100644\nindex 00000000..09e20638\n--- /dev/null\n+++ b/auth-server/src/test/groovy/org/osiam/security/authorization/OsiamUserApprovalHandlerTest.groovy\n@@ -0,0 +1,122 @@\n+package org.osiam.security.authorization\n+\n+import org.osiam.storage.dao.ClientDao\n+import org.osiam.storage.entities.ClientEntity\n+import org.springframework.security.core.Authentication\n+import org.springframework.security.oauth2.provider.AuthorizationRequest\n+import spock.lang.Specification\n+\n+/**\n+ * Created with IntelliJ IDEA.\n+ * User: jtodea\n+ * Date: 09.07.13\n+ * Time: 08:52\n+ * To change this template use File | Settings | File Templates.\n+ */\n+class OsiamUserApprovalHandlerTest extends Specification {\n+\n+    def clienDaoMock = Mock(ClientDao)\n+    def osiamUserApprovalHandler = new OsiamUserApprovalHandler(clientDao: clienDaoMock)\n+    def authorizationRequestMock = Mock(AuthorizationRequest)\n+    def authenticationMock = Mock(Authentication)\n+\n+\n+    def "should only add approval date if it is the correct state and user approved successfully"() {\n+        given:\n+        def clientMock = Mock(ClientEntity)\n+        authorizationRequestMock.getClientId() >> \'example-client\'\n+        clienDaoMock.getClient(\'example-client\') >> clientMock\n+        def approvalParams = [\'user_oauth_approval\':\'true\']\n+        authorizationRequestMock.getApprovalParameters() >> approvalParams\n+        clientMock.getValidityInSeconds() >> 1337\n+\n+        when:\n+        osiamUserApprovalHandler.updateBeforeApproval(authorizationRequestMock, authenticationMock)\n+\n+        then:\n+        clientMock.getExpiry() <= new Date(System.currentTimeMillis() + (1337 * 1000))\n+        1 * clienDaoMock.update(clientMock, \'example-client\')\n+    }\n+\n+    def "should not add approval date if approval param map is empty and not containing key user_oauth_approval"() {\n+        given:\n+        def approvalParams = [:]\n+        authorizationRequestMock.getApprovalParameters() >> approvalParams\n+\n+        when:\n+        osiamUserApprovalHandler.updateBeforeApproval(authorizationRequestMock, authenticationMock)\n+\n+        then:\n+        0 * clienDaoMock.update(_, _)\n+    }\n+\n+    def "should not add approval date if user denies approval"() {\n+        given:\n+        def approvalParams = [\'user_oauth_approval\':\'false\']\n+        authorizationRequestMock.getApprovalParameters() >> approvalParams\n+\n+        when:\n+        osiamUserApprovalHandler.updateBeforeApproval(authorizationRequestMock, authenticationMock)\n+\n+        then:\n+        0 * clienDaoMock.update(_, _)\n+    }\n+\n+    def "should return true if implicit is configured as true to not ask user for approval"() {\n+        given:\n+        def clientMock = Mock(ClientEntity)\n+        authorizationRequestMock.getClientId() >> \'example-client\'\n+        clienDaoMock.getClient(\'example-client\') >> clientMock\n+        clientMock.isImplicit() >> true\n+\n+        when:\n+        def result = osiamUserApprovalHandler.isApproved(authorizationRequestMock, authenticationMock)\n+\n+        then:\n+        result\n+    }\n+\n+    def "should return true if expiry date is valid and user approved client already and must not approve it again"() {\n+        given:\n+        def clientMock = Mock(ClientEntity)\n+        authorizationRequestMock.getClientId() >> \'example-client\'\n+        clienDaoMock.getClient(\'example-client\') >> clientMock\n+        clientMock.getExpiry() >> new Date(System.currentTimeMillis() + (1337 * 1000))\n+\n+        when:\n+        def result = osiamUserApprovalHandler.isApproved(authorizationRequestMock, authenticationMock)\n+\n+        then:\n+        result\n+    }\n+\n+    def "should return false if implicit is not configured and user never approved the client before"() {\n+        given:\n+        def clientMock = Mock(ClientEntity)\n+        authorizationRequestMock.getClientId() >> \'example-client\'\n+        clienDaoMock.getClient(\'example-client\') >> clientMock\n+        clientMock.isImplicit() >> false\n+        clientMock.getExpiry() >> null\n+\n+        when:\n+        def result = osiamUserApprovalHandler.isApproved(authorizationRequestMock, authenticationMock)\n+\n+        then:\n+        !result\n+    }\n+\n+    def "should return false if implicit is not configured and user approval date is expired"() {\n+        given:\n+        def clientMock = Mock(ClientEntity)\n+        authorizationRequestMock.getClientId() >> \'example-client\'\n+        clienDaoMock.getClient(\'example-client\') >> clientMock\n+        clientMock.isImplicit() >> false\n+        clientMock.getExpiry() >> new Date(System.currentTimeMillis() - 100000)\n+\n+        when:\n+        def result = osiamUserApprovalHandler.isApproved(authorizationRequestMock, authenticationMock)\n+\n+        then:\n+        !result\n+    }\n+}\n\\ No newline at end of file\ndiff --git a/auth-server/src/test/groovy/org/osiam/security/controller/AccessConfirmationControllerSpec.groovy b/auth-server/src/test/groovy/org/osiam/security/controller/AccessConfirmationControllerSpec.groovy\nnew file mode 100644\nindex 00000000..a594c1fc\n--- /dev/null\n+++ b/auth-server/src/test/groovy/org/osiam/security/controller/AccessConfirmationControllerSpec.groovy\n@@ -0,0 +1,67 @@\n+/*\n+ * Copyright (C) 2013 tarent AG\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining\n+ * a copy of this software and associated documentation files (the\n+ * "Software"), to deal in the Software without restriction, including\n+ * without limitation the rights to use, copy, modify, merge, publish,\n+ * distribute, sublicense, and/or sell copies of the Software, and to\n+ * permit persons to whom the Software is furnished to do so, subject to\n+ * the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be\n+ * included in all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+ */\n+\n+package org.osiam.security.controller\n+\n+import org.springframework.security.oauth2.provider.AuthorizationRequest\n+import org.springframework.security.oauth2.provider.ClientDetails\n+import org.springframework.security.oauth2.provider.ClientDetailsService\n+import spock.lang.Specification\n+\n+class AccessConfirmationControllerSpec extends Specification{\n+\n+    AccessConfirmationController underTest = new AccessConfirmationController()\n+    ClientDetailsService clientDetailsServiceMock = Mock()\n+\n+    def setup(){\n+        underTest.setClientDetailsService(clientDetailsServiceMock)\n+    }\n+\n+    def "should call clientDetailsService and put auth_request and client into model on access confirmation"(){\n+        given:\n+        AuthorizationRequest request = Mock()\n+        ClientDetails client = Mock()\n+        request.clientId >> "huch"\n+        def model = [\'authorizationRequest\': request]\n+\n+        when:\n+        def result = underTest.getAccessConfirmation(model)\n+\n+        then:\n+        1 * clientDetailsServiceMock.loadClientByClientId("huch") >> client\n+        result.model.get("auth_request") == request\n+        result.model.get("client") == client\n+    }\n+\n+    def "should set error message on handleError"(){\n+        given:\n+        def model = [\'authorizationRequest\': null]\n+\n+        when:\n+        String result = underTest.handleError(model)\n+\n+        then:\n+        result == "oauth_error"\n+        model.get("message") == "There was a problem with the OAuth2 protocol"\n+    }\n+}\ndiff --git a/auth-server/src/test/groovy/org/osiam/security/controller/FbTokenEndpointTest.groovy b/auth-server/src/test/groovy/org/osiam/security/controller/FbTokenEndpointTest.groovy\nnew file mode 100644\nindex 00000000..876d5541\n--- /dev/null\n+++ b/auth-server/src/test/groovy/org/osiam/security/controller/FbTokenEndpointTest.groovy\n@@ -0,0 +1,31 @@\n+package org.osiam.security.controller\n+\n+import org.springframework.http.ResponseEntity\n+import org.springframework.security.oauth2.common.OAuth2AccessToken\n+import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint\n+import spock.lang.Specification\n+\n+class FbTokenEndpointTest extends Specification {\n+    TokenEndpoint tokenEndpoint = Mock(TokenEndpoint)\n+    ResponseEntity tokenEndpointResult = Mock(ResponseEntity)\n+    def underTest = new FbTokenEndpoint(tokenEndpoint: tokenEndpoint)\n+    def body = Mock(OAuth2AccessToken)\n+    def access_token = UUID.randomUUID().toString()\n+\n+    def setup(){\n+        tokenEndpointResult.getBody() >> body\n+    }\n+\n+    def "should manipulate the result of tokenendpoint to be facebook like"(){\n+\n+        when:\n+        def result = underTest.accessToken(null, "authorization-code", null)\n+        then:\n+        1 * tokenEndpoint.getAccessToken(null, "authorization-code", null) >> tokenEndpointResult\n+        1 * body.getValue() >> access_token\n+        1 * body.expiresIn >> 23\n+        result == \'access_token=\'+access_token+\'&expires=23\'\n+\n+    }\n+\n+}\ndiff --git a/auth-server/src/test/groovy/org/osiam/security/helper/FBClientCredentialsTokenEndpointFilterTest.groovy b/auth-server/src/test/groovy/org/osiam/security/helper/FBClientCredentialsTokenEndpointFilterTest.groovy\nnew file mode 100644\nindex 00000000..ce9c8c7c\n--- /dev/null\n+++ b/auth-server/src/test/groovy/org/osiam/security/helper/FBClientCredentialsTokenEndpointFilterTest.groovy\n@@ -0,0 +1,93 @@\n+package org.osiam.security.helper\n+\n+import org.springframework.security.authentication.AuthenticationManager\n+import org.springframework.security.core.Authentication\n+import spock.lang.Specification\n+\n+import javax.servlet.FilterChain\n+import javax.servlet.http.HttpServletRequest\n+import javax.servlet.http.HttpServletResponse\n+\n+class FBClientCredentialsTokenEndpointFilterTest extends Specification {\n+    def authNmanager = Mock(AuthenticationManager)\n+\n+    def underTest = new FBClientCredentialsTokenEndpointFilter(authenticationManager: authNmanager)\n+    HttpServletRequest request = Mock(HttpServletRequest)\n+    HttpServletResponse response = Mock(HttpServletResponse)\n+    def authentication = Mock(Authentication)\n+    FilterChain chain = Mock(FilterChain)\n+\n+\n+\n+\n+    def "should set the url to /fb/oauth/access_token"() {\n+        when:\n+        def underTest = new FBClientCredentialsTokenEndpointFilter()\n+        then:\n+        underTest.filterProcessesUrl == "/fb/oauth/access_token"\n+    }\n+\n+    def "should get the client id and secret"() {\n+        when:\n+        def result = underTest.attemptAuthentication(request, response)\n+        then:\n+        1 * request.getParameter("client_id") >> "client_id"\n+        1 * request.getParameter("client_secret") >> "client_secret"\n+        1 * authNmanager.authenticate(_) >> authentication\n+        result == authentication\n+    }\n+\n+    def "should set null client_secret to empty string"() {\n+        when:\n+        def result = underTest.attemptAuthentication(request, response)\n+        then:\n+        1 * request.getParameter("client_id") >> "client_id"\n+        1 * request.getParameter("client_secret") >> null\n+        1 * authNmanager.authenticate(_) >> authentication\n+        result == authentication\n+    }\n+\n+    def "should create handler"() {\n+        when:\n+        underTest.afterPropertiesSet()\n+        then:\n+        underTest.failureHandler\n+        underTest.successHandler\n+\n+    }\n+\n+\n+    def "should return null when client_id is null"() {\n+        when:\n+        def result = underTest.attemptAuthentication(request, response)\n+        then:\n+        1 * request.getParameter("client_id") >> null\n+        !result\n+    }\n+\n+    def "should call chain.doFilter on successfulAuthentication"() {\n+        when:\n+        underTest.successfulAuthentication(request, response, chain, authentication)\n+        then:\n+        1 * chain.doFilter(request, response)\n+    }\n+\n+    def "should return false on requiresAuthentication when no client_id got submitted"() {\n+        when:\n+        def result = underTest.requiresAuthentication(request, response)\n+        then:\n+        0 * request.getRequestURI()\n+        1 * request.getParameter("client_id") >> null\n+        !result\n+    }\n+\n+    def "should return true on requiresAuthentication when client_id got submitted"() {\n+        when:\n+        def result = underTest.requiresAuthentication(request, response)\n+        then:\n+        1 * request.getContextPath() >> ""\n+        1 * request.getRequestURI() >> "localhost/fb/oauth/access_token"\n+        1 * request.getParameter("client_id") >> "client_id"\n+        result\n+    }\n+}\ndiff --git a/auth-server/src/test/groovy/org/osiam/security/helper/LessStrictRedirectUriAuthorizationCodeTokenGranterTest.groovy b/auth-server/src/test/groovy/org/osiam/security/helper/LessStrictRedirectUriAuthorizationCodeTokenGranterTest.groovy\nnew file mode 100644\nindex 00000000..9c17827b\n--- /dev/null\n+++ b/auth-server/src/test/groovy/org/osiam/security/helper/LessStrictRedirectUriAuthorizationCodeTokenGranterTest.groovy\n@@ -0,0 +1,123 @@\n+package org.osiam.security.helper\n+\n+import org.springframework.security.oauth2.common.exceptions.InvalidClientException\n+import org.springframework.security.oauth2.common.exceptions.InvalidGrantException\n+import org.springframework.security.oauth2.common.exceptions.OAuth2Exception\n+import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException\n+import org.springframework.security.oauth2.provider.AuthorizationRequest\n+import org.springframework.security.oauth2.provider.ClientDetailsService\n+import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices\n+import org.springframework.security.oauth2.provider.code.AuthorizationRequestHolder\n+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices\n+import spock.lang.Specification\n+\n+class LessStrictRedirectUriAuthorizationCodeTokenGranterTest extends Specification {\n+    def tokenService = Mock(AuthorizationServerTokenServices)\n+    def clientDetailsService = Mock(ClientDetailsService)\n+    def authzCodeServices = Mock(AuthorizationCodeServices)\n+    def underTest = new LessStrictRedirectUriAuthorizationCodeTokenGranter(tokenService, clientDetailsService)\n+    AuthorizationRequest authzRequest = Mock(AuthorizationRequest)\n+    AuthorizationRequestHolder storedAuth = Mock(AuthorizationRequestHolder)\n+    AuthorizationRequest authNRequest = Mock(AuthorizationRequest)\n+    def pendingRedirectUri = "localhost:unso"\n+\n+    def setup(){\n+\n+        authzCodeServices.consumeAuthorizationCode("12345") >> storedAuth\n+        storedAuth.getAuthenticationRequest() >> authNRequest\n+        authNRequest.getAuthorizationParameters() >> [redirect_uri: pendingRedirectUri]\n+        underTest.authorizationCodeServices = authzCodeServices\n+        authNRequest.getRedirectUri() >> pendingRedirectUri\n+\n+    }\n+    def set_redirect_uri(redirect_uri){\n+        authzRequest.getAuthorizationParameters() >> [code:"12345", redirect_uri: redirect_uri]\n+    }\n+\n+    def "should continue if the pending redirect uri is equal to the send redirect uri"(){\n+        given:\n+          set_redirect_uri(pendingRedirectUri)\n+\n+        when:\n+          def result = underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        result\n+    }\n+\n+    def "should continue if the pending redirect uri starts with the send redirect uri"(){\n+        given:\n+        set_redirect_uri("localhost")\n+\n+        when:\n+        def result = underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        result\n+    }\n+\n+    def "should continue if the pending redirect uri is null"(){\n+        given:\n+        authNRequest.getAuthorizationParameters() >> [redirect_uri: null]\n+        set_redirect_uri("localhost")\n+        when:\n+        def result = underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+\n+        result\n+    }\n+\n+    def "should abort if the send redirect uri is null but the pending is not"(){\n+        given:\n+        set_redirect_uri(null)\n+        when:\n+        underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        def e = thrown(RedirectMismatchException)\n+        e.message == "Redirect URI mismatch."\n+    }\n+\n+    def "should abort if the pending redirect uri doesn\'t starts with the send redirect uri"(){\n+        given:\n+        set_redirect_uri("localhorst")\n+\n+        when:\n+        underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        def e = thrown(RedirectMismatchException)\n+        e.message == "Redirect URI mismatch."\n+    }\n+\n+    def "should abort if client_id miss matches"(){\n+        given:\n+        set_redirect_uri("localhost")\n+        authNRequest.getClientId() >> "client_id"\n+        authzRequest.getClientId() >> "clientid"\n+\n+        when:\n+        underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        def e = thrown(InvalidClientException)\n+        e.message == "Client ID mismatch"\n+    }\n+\n+    def "should abort if no authorization code got submitted"(){\n+        given:\n+        authzRequest.getAuthorizationParameters() >> [code:null]\n+\n+        when:\n+        underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        def e = thrown(OAuth2Exception)\n+        e.message == "An authorization code must be supplied."\n+    }\n+\n+    def "should abort if no storedAuth got found"(){\n+        given:\n+        authzRequest.getAuthorizationParameters() >> [code:"123456"]\n+\n+        when:\n+        underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        def e = thrown(InvalidGrantException)\n+        e.message == "Invalid authorization code: 123456"\n+    }\n+}\n', 'commit_subject': 'moved authn and authz classes to auth-server project', 'repo_name': 'osiam/osiam', 'committer': {'name': 'jtodea', 'email': 'ac342b6232d4b740e078102a2fb6eeaf3d0867da@googlemail.com', 'time_sec': '1380523350', 'tz_offset': '120', 'date': {'seconds': '1380523350'}}, 'commit_tree': '3fa2879fd1a6bb8db982fd7ae8548c130259256d', 'commit_message': 'moved authn and authz classes to auth-server project\n', 'language_name': 'HTML', 'license': 'mit', 'hunks': '@@ -0,0 +1,123 @@\n+package org.osiam.security.helper\n+\n+import org.springframework.security.oauth2.common.exceptions.InvalidClientException\n+import org.springframework.security.oauth2.common.exceptions.InvalidGrantException\n+import org.springframework.security.oauth2.common.exceptions.OAuth2Exception\n+import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException\n+import org.springframework.security.oauth2.provider.AuthorizationRequest\n+import org.springframework.security.oauth2.provider.ClientDetailsService\n+import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices\n+import org.springframework.security.oauth2.provider.code.AuthorizationRequestHolder\n+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices\n+import spock.lang.Specification\n+\n+class LessStrictRedirectUriAuthorizationCodeTokenGranterTest extends Specification {\n+    def tokenService = Mock(AuthorizationServerTokenServices)\n+    def clientDetailsService = Mock(ClientDetailsService)\n+    def authzCodeServices = Mock(AuthorizationCodeServices)\n+    def underTest = new LessStrictRedirectUriAuthorizationCodeTokenGranter(tokenService, clientDetailsService)\n+    AuthorizationRequest authzRequest = Mock(AuthorizationRequest)\n+    AuthorizationRequestHolder storedAuth = Mock(AuthorizationRequestHolder)\n+    AuthorizationRequest authNRequest = Mock(AuthorizationRequest)\n+    def pendingRedirectUri = "localhost:unso"\n+\n+    def setup(){\n+\n+        authzCodeServices.consumeAuthorizationCode("12345") >> storedAuth\n+        storedAuth.getAuthenticationRequest() >> authNRequest\n+        authNRequest.getAuthorizationParameters() >> [redirect_uri: pendingRedirectUri]\n+        underTest.authorizationCodeServices = authzCodeServices\n+        authNRequest.getRedirectUri() >> pendingRedirectUri\n+\n+    }\n+    def set_redirect_uri(redirect_uri){\n+        authzRequest.getAuthorizationParameters() >> [code:"12345", redirect_uri: redirect_uri]\n+    }\n+\n+    def "should continue if the pending redirect uri is equal to the send redirect uri"(){\n+        given:\n+          set_redirect_uri(pendingRedirectUri)\n+\n+        when:\n+          def result = underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        result\n+    }\n+\n+    def "should continue if the pending redirect uri starts with the send redirect uri"(){\n+        given:\n+        set_redirect_uri("localhost")\n+\n+        when:\n+        def result = underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        result\n+    }\n+\n+    def "should continue if the pending redirect uri is null"(){\n+        given:\n+        authNRequest.getAuthorizationParameters() >> [redirect_uri: null]\n+        set_redirect_uri("localhost")\n+        when:\n+        def result = underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+\n+        result\n+    }\n+\n+    def "should abort if the send redirect uri is null but the pending is not"(){\n+        given:\n+        set_redirect_uri(null)\n+        when:\n+        underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        def e = thrown(RedirectMismatchException)\n+        e.message == "Redirect URI mismatch."\n+    }\n+\n+    def "should abort if the pending redirect uri doesn\'t starts with the send redirect uri"(){\n+        given:\n+        set_redirect_uri("localhorst")\n+\n+        when:\n+        underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        def e = thrown(RedirectMismatchException)\n+        e.message == "Redirect URI mismatch."\n+    }\n+\n+    def "should abort if client_id miss matches"(){\n+        given:\n+        set_redirect_uri("localhost")\n+        authNRequest.getClientId() >> "client_id"\n+        authzRequest.getClientId() >> "clientid"\n+\n+        when:\n+        underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        def e = thrown(InvalidClientException)\n+        e.message == "Client ID mismatch"\n+    }\n+\n+    def "should abort if no authorization code got submitted"(){\n+        given:\n+        authzRequest.getAuthorizationParameters() >> [code:null]\n+\n+        when:\n+        underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        def e = thrown(OAuth2Exception)\n+        e.message == "An authorization code must be supplied."\n+    }\n+\n+    def "should abort if no storedAuth got found"(){\n+        given:\n+        authzRequest.getAuthorizationParameters() >> [code:"123456"]\n+\n+        when:\n+        underTest.getOAuth2Authentication(authzRequest)\n+        then:\n+        def e = thrown(InvalidGrantException)\n+        e.message == "Invalid authorization code: 123456"\n+    }\n+}\n', 'addition_count': 123, 'deletion_count': 0, 'src_file': '/dev/null', 'tgt_file': 'b/auth-server/src/test/groovy/org/osiam/security/helper/LessStrictRedirectUriAuthorizationCodeTokenGranterTest.groovy', 'file_extension': '.groovy', 'before_file': 'ADDFILE', 'message': 'moved authn and authz classes to auth-server project\n', 'author_name': 'jtodea', 'lang': 'groovy'}