Um guia rápido para usar o Cloud Foundry UAA

Um guia rápido para usar o Cloud Foundry UAA

1. Visão geral

Cloud Foundry User Account and Authentication (CF UAA) is an identity management and authorization service. Mais precisamente, é um provedor OAuth 2.0 que permite autenticação e emissão de tokens para aplicativos clientes.

Neste tutorial, vamos cobrir os fundamentos da configuração de um servidor CF UAA. Em seguida, veremos como usá-lo para proteger os aplicativos do Resource Server.

Mas antes, vamos esclarecer o papel do UAA na estrutura de autorizaçãoOAuth 2.0.

2. Cloud Foundry UAA e OAuth 2.0

Vamos começar entendendo como o UAA se relaciona com a especificação OAuth 2.0.

A especificação OAuth 2.0 definefour participants que podem se conectar: ​​um proprietário de recurso, um servidor de recurso, um cliente e um servidor de autorização.

Como um provedor OAuth 2.0, o UAA desempenha o papel deauthorization server.. Isso significaits primary goal is issuing access tokens for client applications and validating these tokens for resource servers.

Para permitir a interação desses participantes, precisamos primeiro configurar um servidor UAA e depois implementar mais dois aplicativos: um como cliente e outro como servidor de recursos.

Usaremos o fluxoauthorization_code grant com o cliente. E usaremos a autorização de token do portador com o servidor de recursos. Para um handshake mais seguro e eficiente, usaremos JWTs assinados como nossoaccess tokens.

3. Configurando um Servidor UAA

Primeiro,we’ll install UAA and populate it with some demo data.

Uma vez instalado, vamos registrar um aplicativo cliente chamadowebappclient. Em seguida, vamos criar um usuário chamadoappuser com duas funções,resource.readeresource.write.

3.1. Instalação

O UAA é um aplicativo da Web Java que pode ser executado em qualquer contêiner de servlet compatível. Neste tutorial, vamosuse Tomcat.

Vamos em frente e implantação dedownload the UAA war and deposit it into our Tomcat:

wget -O $CATALINA_HOME/webapps/uaa.war \
  https://search.maven.org/remotecontent?filepath=org/cloudfoundry/identity/cloudfoundry-identity-uaa/4.27.0/cloudfoundry-identity-uaa-4.27.0.war

Antes de iniciá-lo, no entanto, precisaremos configurar sua fonte de dados e par de chaves JWS.

3.2. Configuração necessária

By default, UAA reads configuration from uaa.yml on its classpath. Mas, como acabamos de baixar o arquivowar, será melhor informar ao UAA um local personalizado em nosso sistema de arquivos.

Podemos fazer isso porsetting the UAA_CONFIG_PATH property:

export UAA_CONFIG_PATH=~/.uaa

Alternativamente, podemos definirCLOUD_FOUNDRY_CONFIG_PATH. Ou, podemos especificar um local remoto comUAA_CONFIG_URL.

Então, podemos copiarUAA’s required configuration em nosso caminho de configuração:

wget -qO- https://raw.githubusercontent.com/cloudfoundry/uaa/4.27.0/uaa/src/main/resources/required_configuration.yml \
  > $UAA_CONFIG_PATH/uaa.yml

Observe que estamos excluindo as três últimas linhas porque as substituiremos em um momento.

3.3. Configurando a fonte de dados

Então, vamos configurar a fonte de dados,where UAA is going to store information about clients.

Para o propósito deste tutorial, vamos usar HSQLDB:

export SPRING_PROFILES="default,hsqldb"

Obviamente, como este é um aplicativo Spring Boot, também podemos especificar isso emuaa.yml as a propriedadespring.profiles.

3.4. Configurando o par de chaves JWS

Como estamos usando JWT,UAA needs to have a private key to sign each JWT that UAA issues.

O OpenSSL simplifica isso:

openssl genrsa -out signingkey.pem 2048
openssl rsa -in signingkey.pem -pubout -out verificationkey.pem

O servidor de autorizaçãosign o JWT com a chave privada, e nosso cliente e servidor de recursosverify essa assinatura com a chave pública.

Vamos exportá-los paraJWT_TOKEN_SIGNING_KEY eJWT_TOKEN_VERIFICATION_KEY:

export JWT_TOKEN_SIGNING_KEY=$(cat signingkey.pem)
export JWT_TOKEN_VERIFICATION_KEY=$(cat verificationkey.pem)

Novamente, poderíamos especificá-los emuaa.yml por meio das propriedadesjwt.token.signing-keyejwt.token.verification-key.

3.5. Iniciando o UAA

Finalmente, vamos começar:

$CATALINA_HOME/bin/catalina.sh run

Neste ponto, devemos ter um servidor UAA funcionando disponível emhttp://localhost:8080/uaa.

Se formos parahttp://localhost:8080/uaa/info, veremos algumas informações básicas de inicialização

3.6. Instalando o UAA Command-Line Client

The CF UAA Command-Line Client is the main tool for administering UAA, mas para usá-lo, precisamosinstall Ruby first:

sudo apt install rubygems
gem install cf-uaac

Então, podemos configuraruaac para apontar para nossa instância em execução do UAA:

uaac target http://localhost:8080/uaa

Observe que se não quisermos usar o cliente de linha de comando, podemos, é claro, usar o cliente HTTP do UAA.

3.7. Preenchendo clientes e usuários usando UAAC

Agora que temosuaac instalado, vamos preencher o UAA com alguns dados de demonstração. At a minimum, we’ll need: A client, a user, and resource.read and resource.write groups.

Então, para fazer qualquer administração, precisamos nos autenticar. Escolheremos o administrador padrão que vem com o UAA,which has permissions to create other clients, users, and groups:

uaac token client get admin -s adminsecret

(Claro,we definitely need to change this account - por meio do arquivooauth-clients.xml - antes do envio!)

Basicamente, podemos ler este comando como: “Dê-me umtoken, usando credenciaisclient com o client_id deadmine um segredosdeadminsecret“.

Se tudo correr bem, veremos uma mensagem de sucesso:

Successfully fetched token via client credentials grant.

O token é armazenado no estado deuaac.

Agora, operando comoadmin, podemos registrar um cliente chamadowebappclient com client add:

uaac client add webappclient -s webappclientsecret \
--name WebAppClient \
--scope resource.read,resource.write,openid,profile,email,address,phone \
--authorized_grant_types authorization_code,refresh_token,client_credentials,password \
--authorities uaa.resource \
--redirect_uri http://localhost:8081/login/oauth2/code/uaa

E também, podemos registrar um usuário chamadoappuser comuser add:

uaac user add appuser -p appusersecret --emails [email protected]

A seguir, vamos adicionar dois grupos -resource.read eresource.write - usando com group add:

uaac group add resource.read
uaac group add resource.write

E finalmente, vamos atribuir esses grupos aappuser com member add:

uaac member add resource.read appuser
uaac member add resource.write appuser

Ufa! Então, o que fizemos até agora é:

  • UAA instalado e configurado

  • Instaladouaac

  • Adicionado um cliente demo, usuários e grupos

Então, vamos manter em mente essas informações e pular para a próxima etapa.

4. Cliente OAuth 2.0

Nesta seção,we’ll use Spring Boot to create an OAuth 2.0 Client application.

4.1. Configuração do aplicativo

Vamos começar acessandoSpring Initializre gerando um aplicativo da web Spring Boot. Escolhemos apenas os componentesWebeOAuth2 Client:


    org.springframework.boot
    spring-boot-starter-web


    org.springframework.boot
    spring-boot-starter-oauth2-client

Neste exemplo, usamosversion 2.1.3 de Spring Boot.

Em seguida,we need to register our client, webapp*client*.

Muito simplesmente, precisaremos fornecer ao aplicativoclient-id,client-secret,e UAA'sissuer-uri. Também especificaremos os escopos OAuth 2.0 que este cliente deseja que o usuário conceda a ele:

#registration
spring.security.oauth2.client.registration.uaa.client-id=webappclient
spring.security.oauth2.client.registration.uaa.client-secret=webappclientsecret
spring.security.oauth2.client.registration.uaa.scope=resource.read,resource.write,openid,profile

#provider
spring.security.oauth2.client.provider.uaa.issuer-uri=http://localhost:8080/uaa/oauth/token

Para obter mais informações sobre essas propriedades, podemos dar uma olhada na documentação Java dos beansregistrationeprovider.

E como já estamos usando a porta 8080 para UAA, vamos executá-la na 8081:

server.port=8081

4.2. Conecte-se

Agora, se acessarmos o caminho/login, devemos ter uma lista de todos os clientes cadastrados. No nosso caso, temos apenas um cliente registrado:

image Clicar no link nos redirecionará para a página de login do UAA:

image

Aqui, vamos fazer o login comappuser/appusersecret.

O envio do formulário deve nos redirecionar para um formulário de aprovação onde o usuário pode autorizar ou negar acesso ao nosso cliente:

image

O usuário pode então conceder quais privilégios ele deseja. Para nossos propósitos,we’ll select everything except resource:write.

O que quer que o usuário verifique será o escopo no token de acesso resultante.

Para provar isso, podemos copiar o token mostrado no caminho do índice,http://localhost:8081, e decodificá-lo usandoJWT debugger. We should see the scopes we checked on the approval page:

{
  "jti": "f228d8d7486942089ff7b892c796d3ac",
  "sub": "0e6101d8-d14b-49c5-8c33-fc12d8d1cc7d",
  "scope": [
    "resource.read",
    "openid",
    "profile"
  ],
  "client_id": "webappclient"
  // more claims
}

Depois que nosso aplicativo cliente recebe esse token, ele pode autenticar o usuário e ele terá acesso ao aplicativo.

Agora,an app that doesn’t show any data isn’t very useful, so our next step will be to stand up a resource server - que contém os dados do usuário - e conecte o cliente a ele.

O servidor de recursos concluído terá duas APIs protegidas: uma que requer o escoporesource.read e outra que requerresource.write.

O que veremos é quethe client, using the scopes we granted, will be able to call the read API but not write.

5. Servidor de Recursos

O servidor de recursos hospeda os recursos protegidos do usuário.

Ele autentica clientes por meio do cabeçalhoAuthorization e em consulta com um servidor de autorização - em nosso caso, é o UAA.

5.1. Configuração do aplicativo

Para criar nosso servidor de recursos, usaremosSpring Initializr novamente para gerar um aplicativo da web Spring Boot. Desta vez, vamos escolher os componentesWebeOAuth2 Resource Server:


    org.springframework.boot
    spring-boot-starter-oauth2-resource-server


    org.springframework.boot
    spring-boot-starter-web

Tal como acontece com o aplicativo cliente, estamos usandothe version 2.1.3 de Spring Boot.

A próxima etapa é indicar a localização do CF UAA em execução no arquivoapplication.properties:

spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/uaa/oauth/token

Claro, vamos escolher uma nova porta aqui também. 8082 funcionará bem:

server.port=8082

E é isso! Devemos ter um servidor de recursos funcionando e, por padrão, todas as solicitações exigirão um token de acesso válido noAuthorization header.

5.2. Protegendo APIs de servidor de recursos

A seguir, vamos adicionar alguns pontos de extremidade que vale a pena proteger.

Adicionaremos umRestController com dois endpoints, um autorizado para usuários com escoporesource.read e outro para usuários com escoporesource.write scope:

@GetMapping("/read")
public String read(Principal principal) {
    return "Hello write: " + principal.getName();
}

@GetMapping("/write")
public String write(Principal principal) {
    return "Hello write: " + principal.getName();
}

A seguir,we’ll override the default Spring Boot configuration para proteger os dois recursos:

@EnableWebSecurity
public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter {

   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
        .antMatchers("/read/**").hasAuthority("SCOPE_resource.read")
        .antMatchers("/write/**").hasAuthority("SCOPE_resource.write")
        .anyRequest().authenticated()
      .and()
        .oauth2ResourceServer().jwt();
   }
}

Note that the scopes supplied in the access token are prefixed with SCOPE_ when they are translated to a Spring Security GrantedAuthority.

5.3. Solicitando um recurso protegido de um cliente

Do aplicativo cliente, chamaremos os dois recursos protegidos usandoRestTemplate. Antes de fazer a solicitação, recuperamos o token de acesso do contexto e o adicionamos ao cabeçalhoAuthorization:

private String callResourceServer(OAuth2AuthenticationToken authenticationToken, String url) {
    OAuth2AuthorizedClient oAuth2AuthorizedClient = this.authorizedClientService.
      loadAuthorizedClient(authenticationToken.getAuthorizedClientRegistrationId(),
      authenticationToken.getName());
    OAuth2AccessToken oAuth2AccessToken = oAuth2AuthorizedClient.getAccessToken();

    HttpHeaders headers = new HttpHeaders();
    headers.add("Authorization", "Bearer " + oAuth2AccessToken.getTokenValue());

    // call resource endpoint

    return response;
}

Observe, porém, que podemos remover esse clichê seuse WebClient instead of RestTemplate.

Em seguida, adicionaremos duas chamadas aos endpoints do servidor de recursos:

@GetMapping("/read")
public String read(OAuth2AuthenticationToken authenticationToken) {
    String url = remoteResourceServer + "/read";
    return callResourceServer(authenticationToken, url);
}

@GetMapping("/write")
public String write(OAuth2AuthenticationToken authenticationToken) {
    String url = remoteResourceServer + "/write";
    return callResourceServer(authenticationToken, url);
}

Como esperado,the call of the /read API will succeed, but not the /write one. O status HTTP 403 nos diz que o usuário não está autorizado.

6. Conclusão

Neste artigo, começamos com uma breve visão geral do OAuth 2.0, pois ele é a base do UAA, um servidor de autorização OAuth 2.0. Em seguida, o configuramos para emitir tokens de acesso para um cliente e proteger um aplicativo de servidor de recursos.

O código-fonte completo dos exemplos está disponívelover on Github.