Warning
This page is located in archive.

Stažení aplikace

Aplikaci můžete stáhnout zde: auth.zip

Tento příklad využívá pro autentizaci uzivatele uživatelské role definované na serveru Jboss.

Vytvoření uživatele

Uživatele můžete vytvořit pomocí příkazu ve složce:

 JBOSS_HOME/bin/add-user.bat   nebo   JBOSS_HOME/bin/add-user.sh
 

Po spuštění tohoto příkazu nejprve vyberte “Application user” (volba b).

Realm nechte na defaulní hodnotu (ApplicationRealm), slouží k rozlišení ke které aplikaci uživatel patří.

Zadejte název a heslo uživatele a nakonec ho přidělte do skupiny manager.

Vytvořte ještě jednoho uživatele, kterého přidělíte do skupiny admin.

Aplikace

Po rozbalení staženého příkladu si prohledněte deskriptor (web.xml). Obsahuje nastavení autentizace uživatelů.

Toto bezpečnostní omezení definuje, že všechny URL adresy pro metody POST a DELETE vyžadují autentizaci uživatele.

  <!-- Metody DELETE a POST vyžadují přihlášení -->
  <security-constraint>      
      <web-resource-collection>
          <web-resource-name>DeleteUser</web-resource-name>          
          <url-pattern>/*</url-pattern>
          <http-method>DELETE</http-method>
          <http-method>POST</http-method>
      </web-resource-collection>
      <auth-constraint>
          <role-name>admin</role-name>
          <role-name>manager</role-name>
      </auth-constraint>
  </security-constraint>
  

Zde je konfigurace metody autentizace. Pro přihlášení je použita metoda BASIC. Real aplikace je “ApplicationRealm”.

  <!-- Konfigurace loginu -->
  <login-config>
      <auth-method>BASIC</auth-method>
      <realm-name>ApplicationRealm</realm-name>
  </login-config>
  

Konfigurace Jersey má nastavený filter “RolesAllowedResourceFilter”. Tento filter kontroluje zda mají uživatelé právo pro jednotlivé operace (Kontroluje zda má aktuálně přihlášený uživatel přidělenu roli definovanou v anotaci @RolesAllowed).

   <init-param>
      <!-- filter skenující povolené role pro jednotlivé metody -->
      <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
      <param-value>com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory</param-value>
   </init-param>
   

V deskriptoru také musí být definované role, které aplikace využívá pro zabezpečení:

  <!-- Security role -->
  <security-role>  
      <role-name>admin</role-name>  
  </security-role>    
  <security-role>
      <role-name>manager</role-name>
  </security-role> 

Poslední konfigurace aplikace je v souboru jboss-web.xml. Tento soubor, kromě nastavení cesty obsahuje také security domain. Ta určuje jaký způsob kontroly přihlašovacích údajů server používá.

   <?xml version="1.0" encoding="UTF-8"?>
   <jboss-web>
     <context-root>/aos-rest-users-server</context-root>
     <security-domain>java:/jaas/other</security-domain>
   </jboss-web>

Konfigurace security domain musí být v nastavení samotného Jboss serveru. Defaultní konfigurace (standalone.xml) vypadá takto (není nutné ji měnit):

 <security-domain name="other" cache-type="default">
     <authentication>
        <login-module code="Remoting" flag="optional">
           <module-option name="password-stacking" value="useFirstPass"/>
        </login-module>
        <login-module code="RealmUsersRoles" flag="required">
           <module-option name="usersProperties" value="${jboss.server.config.dir}/application-users.properties"/>
           <module-option name="rolesProperties" value="${jboss.server.config.dir}/application-roles.properties"/>
           <module-option name="realm" value="ApplicationRealm"/>
           <module-option name="password-stacking" value="useFirstPass"/>
        </login-module>
     </authentication>
 </security-domain>

Pro autentizaci uživatelů se používají dva soubory application-users.properties a application-roles.properties. Tyto soubory obsahují uživatele, jejich hesla a role. Aby bylo možné rozlišit aplikaci je k heslu přidán název realmu (ApplicationRealm) a do finální podoby je heslo zahashováno.

Kód aplikace

Do původního příkladu přibyly dvě metody pro smazání a úpravu uživatele. Smazání uživatele (metoda DELETE) vypadá takto:

  
  @DELETE
  @Path("/{nickname}/")
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  @RolesAllowed({"admin"})
  public MappingUser delete(@PathParam("nickname") String nickname) {
      UserEntity userEntity = AOSMemoryDB.deleteUserByNick(nickname);
      if (userEntity == null) {
          throw new NotFoundException("User not found");
      }
      return new MappingUser(userEntity, uriInfo.getAbsolutePathBuilder());
  }

Všiměte si anotace @RolesAllowed ta udává, že tuto operaci může provést pouze uživatel, který je v roli “admin”.

Metoda pro úpravu uživatelů umožňuje pouze změnit heslo. K této operaci musí klient znát původní heslo uživatele a poslat jej v hlavičce X-Password. V opačeném případě získá pouze chybu 403. Metoda hlavičku získá přímo jako proměnnou password pomocí anotace @HeaderParam(“x-Password”). Tímto způsobem můžete získat libovolnou HTTP hlavičku.

  @PUT
  @Path("/{nickname}/")
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  public MappingUser updateUser(MappingUser user, @PathParam("nickname") String nickname, @HeaderParam("x-Password") String password) {
      UserEntity userEntity = AOSMemoryDB.getUserByNick(nickname);
      if (userEntity == null) {
          throw new NotFoundException("User not found");
      }
      if (!userEntity.getPass().equals(password)) {
          throw new AccessDeniedRequestException("Access denied");
      }
      userEntity.setPass(user.getPassword());
      return new MappingUser(userEntity, uriInfo.getAbsolutePathBuilder());
  }

HTML stránka pomocí jersey

Pokud chcete na jedné url adrese poskytovat JSON/XML i HTML je nutné nastavit Jersey jako filter místo servletu. Také je nutné přidat několik parametrů, aby Jersey dokázala nalézt jsp nebo statické soubory.

  <filter>
      <filter-name>Rest</filter-name>
      <filter-class>com.sun.jersey.spi.container.servlet.ServletContainer</filter-class>
      <init-param>
          <!-- filter skenující povolené role pro jednotlivé metody -->
          <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
          <param-value>com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory</param-value>
      </init-param>     
      <init-param>
          <!-- filter skenující povolené role pro jednotlivé metody -->
          <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
          <param-value>com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory</param-value>
      </init-param>      
      <init-param>
          <!-- regex na exclusion jiných zdrojů -->
          <param-name>com.sun.jersey.config.property.WebPageContentRegex</param-name>
          <param-value>/(images|js|styles|(WEB-INF/jsp))/.*</param-value>
      </init-param>
      <init-param>
          <!-- umožnit vracení POJO a jejich automatickou konverzi podle zvoleného content type -->
          <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
          <param-value>true</param-value>
      </init-param>
      <init-param>
          <!-- home pro JSP stránky -->
          <param-name>com.sun.jersey.config.property.JSPTemplatesBasePath</param-name>
          <param-value>/WEB-INF/jsp</param-value>
      </init-param>
  </filter>

Vygenerované html pak můžete získat z jsp například pomocí Viewable. Jsp stránka musí být v adresáři /WEB-INF/jsp. Všimněte si, že metoda resources má stejnou URL adresu jako metoda webPage, pouze vrací jiný Content-type. Tato metoda vytváří JSON/XML ze seznamem URL adres jednotlivých zdrojů.

 
  @GET
  @Produces({ MediaType.TEXT_HTML })
  @Path("/")
  public Response webPage() {
      return Response.ok( new Viewable("/index"), MediaType.TEXT_HTML )
              .build();
  }
  
  @GET
  @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
  @Path("/")
  public List<MappingResource> resources() {
      List<MappingResource> resources = new ArrayList<MappingResource>();
      resources.add(new MappingResource("users", 
              uriInfo.getAbsolutePathBuilder().path("users")
              .build().getPath()));
      return resources;
  }
courses/a4m36aos/cviceni/class_15_10_2015_2.txt · Last modified: 2015/10/14 17:17 by kopriste