====== Tutorial para simular localmente o SSO CASino utilizando Docker ======
Este tutorial tem por objetivo criar um servidor local que responda de forma semelhante ao
servidores CAS disponíveis em ambiente externo, mas possa ser configurado localmente.
Será abordada a construção da imagem na plataforma docker, sua execução e a
configuração dos logins no SSO.
É necessário ter algum conhecimento prévio sobre docker e ciência de quais campos que
virão das contas do SSO.
===== 1. Construção da imagem docker =====
Os arquivos para a construção da imagem estão disponíveis no git.
Criaremos a imagem no docker e levantaremos o container com a imagem.
==== 1.1. Baixar os arquivos disponíveis ====
$ git clone https://git.ufrj.br/josueresende/mock-casino.git
^ Descrição dos Arquivos ^^
|\Dockerfile | Receita para a geração da imagem com Ruby 2.3 Foi utilizado como base em um projeto((https://hub.docker.com/r/kwokhou/casinoapp/dockerfile)) no site hub do docker. |
|\Gemfile | Descreve as dependências para o programa em Ruby |
|\cas.yml | Configuração de autenticadores e logins do programa |
|\database.yml | Utilizado durante a instalação |
|\certificate_authority-password_1234-privateKey.key | Chave privada da 'Certificate Authority' - senha: 1234 |
|\certificate_authority-help.txt | Informações sobre a criação da 'Certificate Authority' e ajuda para os testes em Java |
|\certificate_authority-rootCertificate.pem | Certificado da 'Certificate Authority' |
|\certificate_authority-rootCertificate.srl | Arquivo com o serial criado (-CAcreateserial ) |
|\casino.key | Private Key - Chave privada para o serviço |
|\casino.csr | Certificate Signing Request |
|\casino.ext | Extra - Dados para geração do certificado do serviço pela autoridade certificadora |
|\docker-entrypoint.sh | Shell Script para gerar o certificado do serviço durante inicialização do container, alterando a linha IP.1 de acordo com o IP da máquina |
| | |
Há como substituir os arquivos ou diretórios através da montagem de volumes quando for
levantar o container mais à frente.
O certificado SSL será gerado durante a inicialização do container.
==== 1.2. Construindo a imagem no docker ====
$ sudo docker image build --tag=mock-casino-image mock-casino
Obs: Favor reportar quaisquer problemas na geração da imagem.
==== 1.3. Levantando o container utilizando a imagem criada ====
Ao levantar o container, é possível vincular os arquivos internos a arquivos externos
informando como volume.
Podemos vincular um arquivo de configuração ‘**cas.yml**’ externo para aquele que se encontra dentro do container em **/var/www/app/casino_app/config/cas.yml**.
Para configurar esse arquivo externo, veja a seção [[mockcas#configurando_logins_no_casino|Configurando logins no CASino]].
Abaixo, assumirei que o arquivo externo existe em: /mnt/fs_docker/mocks/cas.yml.
Através da linha de comando do docker((https://docs.docker.com/engine/reference/commandline/container_run/)) levantamos o container. Obs: Abaixo temos apenas uma linha de comando.
$ sudo docker container run
--name=mock-casino-container
--detach
--volume=/mnt/fs_docker/mocks/cas.yml:/var/www/app/casino_app/config/cas.yml
--publish=443:443
mock-casino-image
==== 1.4. Testando o CAS ====
Entre no seu browser, através do endereço ''https://127.0.0.1''.
Se estiver correto irá aparecer a tela a seguir.
{{ :infotic:projetos:mockcas-testando-cas.png?400 |}}
===== 2. Configurando logins no CASino =====
O arquivo de configuração do SSO CASino((http://casino.rbcas.com/docs/configuration/)), cas.yml, está em YAML((https://pt.wikipedia.org/wiki/YAML)) que é o formato
utilizado como padrão de serialização em Ruby.
Para termos o arquivo modificado, altere ou copie o cas.yml baixado .
Nesse arquivo, iremos alterar a coleção ‘users’ onde a chave é o login e abaixo ficam os
campos de cada usuário. **As partes exibidas abaixo são apenas um trecho do arquivo completo.**
development:
<<: *defaults
authenticators:
static:
class: "CASino::StaticAuthenticator"
options:
users:
"login-do-usuario":
nome: "nome-do-usuario"
password: "senha-do-usuario"
email: "email-do-usuario"
outro-campo: "bla bla bla ..."
"login-do-usuario-2":
nome: "nome-do-usuario-2"
password: "senha-do-usuario-2"
email: "email-do-usuario-2"
outro-campo: "bla bla bla ..."
Modifique os campos do usuário na lista 'users' com os campos esperados respeitando a indentação.
O único campo obrigatório é o password, que serve para autenticar e não retorna na resposta.
users:
"12345678909":
nome: "JOAQUIM SILVA XAVIER"
password: "123"
email: "joaquimxavier@dominio.br"
IdentificacaoUFRJ: "12345678909"
matricula_siape: "123"
registro_sira: "123"
grupos: "tecnico_admin:aluno_pos"
eh_tec_admin: "1"
eh_aluno_grad: "---..."
eh_aluno_pos: "0"
eh_professor: "---..."
ativo: "1"
É necessário reiniciar o SSO CASino para que as mudanças tenham efeito.
**Obs**:
Para quem usa o CAS para autenticação e pega o perfil de usuário que vem de lá, a melhor maneira é pegar pelo atributo "grupos", e ali terá uma string com todos os perfis que o usuário já teve na UFRJ.
Os atributos "eh_" só indicam se está em atividade no perfil.
===== 3. Testes no ambiente com Laravel Dusk =====
Após as instalações do [[mockcas#anexolaravel_dusk_basico|Dusk]]((https://wiki.tic.ufrj.br/doku.php?id=infotic:projetos:dev:lang:php:laravel:testes:dusk)) e execução do [[mockcas#anexochromedriver|Chromedriver]] podemos realizar testes no ambiente.
Nosso **.env.dusk** terá pelo menos as seguintes linhas
# utilizo essa variável no script
CHROMEDRIVER=http://172.18.0.1:9515
ROOT_USERNAME=12345678912
ROOT_PASSWORD=123
# abaixo seguem as utilizadas no projeto (.env)
APP_ENV=dusk
APP_DEBUG=true
APP_URL=http://172.18.0.10/
CAS_HOST=172.18.0.30
CAS_CONTEXT=""
CAS_PROXY=true
Para esta classe de teste,vamos sobrescrever criar os métodos driver/prepare/setUp na classe DuskTestCase, e incluir mais um método que insere o texto no input e confere seu valor.
...
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
.
.
.
protected function driver()
{
$options = new ChromeOptions();
$options->addArguments([
'--disable-gpu',
'--window-size=1920,1080',
'--verbose',
'--lang=pt-BR', // idioma do browser
// '--headless', // <- browser sem tela
]);
$options->setExperimentalOption(
'prefs',
['intl.accept_languages' => 'pt-BR']
);
return RemoteWebDriver::create(
env('CHROMEDRIVER', NULL),
DesiredCapabilities::chrome()->setCapability(ChromeOptions::CAPABILITY, $options)
);
}
public static function prepare()
{
static::startChromeDriver();
}
protected function setUp()
{
$this->browse( function (Browser $browser) {
$browser->visit(env('APP_URL', ''));
# Fig: 1
// $browser->resize( 640, 480); sleep(5); // redimensionamentos de tela
// $browser->resize( 800, 600); sleep(5);
// $browser->resize(1024, 768); sleep(5);
$browser->maximize();
sleep(1);
//
{ // parte da rotina para fechar a DEBUGBAR
$buttonDebugBares = $browser->driver->findElements(
WebDriverBy::className('phpdebugbar-close-btn')
);
foreach ($buttonDebugBares as $buttonDebugBar) {
if ($buttonDebugBar->isDisplayed()) $buttonDebugBar->click();
}
if (count($buttonDebugBares) > 0) sleep(2);
}
});
return parent::setUp(); // TODO: Change the autogenerated stub
}
...
// rotina que confere a digitação do texto em input
protected function entrarDadosCorretamente($id, $value)
{
$this->browse( function (Browser $browser) use($id, $value) {
do {
$browser->type($id, $value);
sleep(1);
if ($browser->inputValue($id) == $value) break;
} while(true);
});
}
...
/**
* @group T00
* @group US01-0
* @throws \Throwable
*/
public function test_Login_no_CAS()
{
$username = env('ROOT_USERNAME');
$password = env('ROOT_PASSWORD');
$this->browse( function (Browser $browser) use($username, $password) {
$browser->assertSee('Acesso administrativo');
$browser->clickLink('Acesso administrativo');
# Fig: 2
self::entrarDadosCorretamente('username', $username);
self::entrarDadosCorretamente('password', $password);
$browser->click('button[type=submit]');
# Fig: 3
$browser->assertDontSee('Acesso administrativo');
});
}
Passos na figuras a seguir, em ordem:
{{ :infotic:projetos:conhecendo-a-ufrj-inicio.png?nolink&600 |Figura 1 - setUp}}
{{ :infotic:projetos:mockcas-login-0.png?nolink&600 |Figura 2 - test_Login_no_CAS() após click no link de acesso}}
{{ :infotic:projetos:conhecendo-a-ufrj-root-logado-0.png?nolink&600 |Figura 3 - test_Login_no_CAS() após submit}}
As telas acima são do projeto [[https://git.ufrj.br/infotic/NovoConhecendoUFRJ/tree/DEV/tests/Browser|Novo Conhecendo a UFRJ]].
----
===== Anexo: Portainer – Docker Compose file format v2 =====
Para execução do container no portainer editamos a stack que utilizará o mock.
Abaixo como exemplo na sua seção services((https://docs.docker.com/compose/compose-file/compose-file-v2/)), segue:
casino:
container_name: mock-casino-container
hostname: casino
image: mock-casino-image
restart: unless-stopped
mem_limit: 1G
expose:
- 443
networks:
default:
ipv4_address: 172.18.0.30
volumes:
- /mnt/fs_docker/mocks/cas.yml:/var/www/app/casino_app/config/cas.yml
Obs: Nesse exemplo existem configurações que necessitam estar disponíveis anteriormente, como a rede.
----
===== Anexo: Exemplos de comando em Docker =====
# Listar todos os containers em execução
$ sudo docker container ps
# Parar a execução do container
$ sudo docker container stop mock-casino-container
# Remover um container
$ sudo docker container rm mock-casino-container
# Executa o container e define que sempre será reiniciado, a menos que que seja parado
$ sudo docker container run --restart=unless-stopped mock-casino-container
----
===== Anexo: Laravel Dusk (Básico) =====
==== 1. Instalando ====
Dentro do projeto Laravel você deve incluir o componente do Laravel Dusk((https://laravel.com/docs/5.4/dusk))
# diretórios antes
tests
├── CreatesApplication.php
├── Feature
│ └── ExampleTest.php
├── TestCase.php
└── Unit
└── ExampleTest.php
$ composer require --dev laravel/dusk
$ php artisan dusk:install
# diretórios depois
tests
├── Browser
│ ├── Components
│ ├── console
│ ├── ExampleTest.php
│ ├── Pages
│ │ ├── HomePage.php
│ │ └── Page.php
│ └── screenshots
├── CreatesApplication.php
├── DuskTestCase.php
├── Feature
│ └── ExampleTest.php
├── TestCase.php
└── Unit
└── ExampleTest.php
==== 2. Configurando ====
Você precisa criar um arquivo de configuração de ambiente para o dusk na raiz do projeto como **.env.dusk** que pode ser igual **.env** dependendo do for precisar somente com o Laravel Dusk.
==== 3. Criando testes ====
$ php artisan dusk:make T00_Test
# Cria uma classe de teste com o nome solicitado dentro do diretório
# “tests/Browser” que estende “tests/DuskTestCase.php”
tests/
├── Browser
│ ├── Components
│ ├── console
│ ├── ExampleTest.php
│ ├── Pages
│ │ ├── HomePage.php
│ │ └── Page.php
│ ├── screenshots
│ └── T00_Test.php
├── CreatesApplication.php
├── DuskTestCase.php
├── Feature
│ └── ExampleTest.php
├── TestCase.php
└── Unit
└── ExampleTest.php
==== 4. Executando ====
Necessário ter o [[mockcas#anexochromedriver|Chromedriver]] executando.
# O comando abaixo executa os testes seguindo a ordem alfabética de todos os testes
$ php artisan dusk
É possível executar por grupo de testes adicionando o parâmetro “--group”, que trabalha associado a anotação @group encontrada no comentário de um função ‘test’
$ php artisan dusk --group=T00
----
===== Anexo: Chromedriver =====
==== Instalando ====
- Baixar a aplicação em http://chromedriver.chromium.org/downloads (Obs: Preferência pela versão 2.*)
- Extrair o arquivo ZIP
- Disponibilizar o binário extraído como executável no PATH do ambiente (Ex: /usr/local/bin)
==== Executando ====
$ /usr/local/bin/chromedriver --whitelisted-ips * &
#
# whitelisted-ips - lista de IPs com conexões permitidas