====== 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