如何实现提供程序以创建身份验证

时间:2016-02-11 10:19:35

标签: security java-ee jax-rs restful-authentication

我的J2E应用程序存在很大问题。它是一个实现RESTFUL API的应用程序。我希望通过身份验证插入一些安全性来区分普通用户和管理员。在认证实现之前,@ GET @POST等..方法是否有效。这是我的提供商的代码:

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.m2acsi.util;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.inject.Inject;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import org.m2acsi.boundary.AdminRessource;
import org.m2acsi.entity.Admin;

/**
 *
 * @author Michel
 */
@Provider
public class AutentificatorFilter implements ContainerRequestFilter{

private AdminRessource ressource;

@Context
private ResourceInfo resourceInfo;
private static final String AUTORISATION="authorization", SCHEMA="Basic";
private static final Response ACCESS_DENIED= Response.status(Response.Status.UNAUTHORIZED).build();
private static final Response ACCESS_FORBIDEN= Response.status(Response.Status.FORBIDDEN).build();

@Override
public void filter(ContainerRequestContext rc){
    Method method = resourceInfo.getResourceMethod();
    if (!method.isAnnotationPresent(PermitAll.class)){ //On teste si la méthode renvoyé (GET, POST...) est permise pour tous
        if(method.isAnnotationPresent(DenyAll.class)){ //On teste si la méthode est interdite pour tous le monde, dans ce cas on refuse l'accès
            rc.abortWith(ACCESS_FORBIDEN);
            return;
        }   
    }
    final MultivaluedMap<String,String> headers = rc.getHeaders();
    final List<String> autorisation = headers.get(AUTORISATION);
    if (autorisation == null || autorisation.isEmpty()){
        throw new NotAuthorizedException("BASIC realm=\"passport\"");
    }
    final String motdepasseencode = autorisation.get(0).replaceFirst(SCHEMA+" ","");
    String userplusmdp = new String(Base64.getDecoder().decode(motdepasseencode.getBytes()));
    final StringTokenizer tokenizer = new StringTokenizer(userplusmdp,":");
    final String user = tokenizer.nextToken();
    final String mdp = tokenizer.nextToken();
    if (method.isAnnotationPresent(RolesAllowed.class)){
        RolesAllowed roles = method.getAnnotation(RolesAllowed.class);
        Set<String> rolesSet = new HashSet<>(Arrays.asList(roles.value()));
        if(!isUserAllowed(user,mdp,rolesSet)){
            rc.abortWith(ACCESS_DENIED);
        }
    }
}

//On test si l'utilisateur qui souhaite faire une demande particulière est bien admin
private boolean isUserAllowed(final String user, final String mdp, final Set<String> roles){
    boolean isAllowed = false;
    List<Admin> admin = this.ressource.getAll();
    String userRole = "ADMIN";
    for (Admin a : admin) {
        if(user.equals(a.getLogin()) && mdp.equals(a.getMdp())){
            if(roles.contains(userRole)){
                isAllowed = true;
                break;
            }
        }
    }
    return isAllowed;
}
}

我的不同实体和资源的代码:

Demande:

    /*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.m2acsi.entity;

import java.io.Serializable;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.security.DeclareRoles;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.Pattern;
import org.m2acsi.util.TokenGenerator;

/**
 *
 * @author Divi
 */
@Entity
@ManagedBean
@ViewScoped
@NamedQuery(name = "Demande.findAll", query = "SELECT d FROM Demande d")
@Table(name = "DEMANDE")
@DeclareRoles("ADMIN")
public class Demande implements Serializable{

    @Id
    @GeneratedValue
    @Column
    private long demande_id;

    @Column
    @Pattern(regexp ="^([a-z]+(( |')[a-z]+)*)+([-]([a-z]+(( |')[a-z]+)*)+)*$", 
            message ="Merci de saisir un nom valide")
    private String nom;

    @Column
    @Pattern(regexp ="^([a-z]+(( |')[a-z]+)*)+([-]([a-z]+(( |')[a-z]+)*)+)*$", 
            message ="Merci de saisir un prénom valide")
    private String prenom;

    @Column
    private String sexe;

    @Column
    @Pattern(regexp ="([a-zA-Z0-9 [-] ]*)", 
            message ="Merci de saisir un nom valide")
    private String adresse;

    @Column
    private String num_pass;

    @Column
    private String pays;

    @Column
    @Pattern(regexp="^(0?[0-9]|[12][0-9]|3[01])/(0?[0-9]|1[012])/((?:19|20)[0-9]{2})$",
             message ="Merci de saisir une date de naissance valide")
    private String datenaiss;

    @Column
    private String delivrance;

    @Column
    private Date expiration;

    @Column
    private String statut;

    @Column
    private String token;

    @OneToMany (cascade=CascadeType.ALL, mappedBy="demande")
    private List<Action> actions = new ArrayList<>();

    public Demande() {
    }

    public Demande(String nom, String prenom, String sexe, 
            String adresse, String pays, String datenaiss) throws ParseException {
        this.nom = nom;
        this.prenom = prenom;
        this.sexe = sexe;
        this.adresse = adresse;
        this.pays = pays;
        this.datenaiss = datenaiss;
        this.statut = "Début";
        this.delivrance = null;
        this.expiration = null;
        this.token = TokenGenerator.generateRandom();
    }


    public long getId() {
        return demande_id;
    }

    public void setId(long id) {
        this.demande_id = id;
    }

    public String getStatut() {
        return statut;
    }

    public void setStatut(String statut) {
        this.statut = statut;
    }

    public List<Action> getActions() {
        return actions;
    }

    public void setActions(List<Action> actions) {
        this.actions = actions;
    }

    public String getNom() {
        return nom;
    }

    public void setNom(String nom) {
        this.nom = nom;
    }

    public String getPrenom() {
        return prenom;
    }

    public void setPrenom(String prenom) {
        this.prenom = prenom;
    }

    public String getSexe() {
        return sexe;
    }

    public void setSexe(String sexe) {
        this.sexe = sexe;
    }

    public String getAdresse() {
        return adresse;
    }

    public void setAdresse(String adresse) {
        this.adresse = adresse;
    }

    public String getPays() {
        return pays;
    }

    public void setPays(String pays) {
        this.pays = pays;
    }

    public String getDatenaiss() {
        return datenaiss;
    }

    public void setDatenaiss(String datenaiss) {
        this.datenaiss = datenaiss;
    }

    public String getDelivrance() {
        return delivrance;
    }

    public void setDelivrance(String delivrance) {
        this.delivrance = delivrance;
    }

    public Date getExpiration() {
        return expiration;
    }

    public void setExpiration(Date expiration) {
        this.expiration = expiration;
    }

    public void addAction(Action a) {
        this.actions.add(a);
    }



}

DemandeRessource:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.m2acsi.boundary;

import java.util.List;
import javax.annotation.security.DeclareRoles;
import javax.ejb.Stateless;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceContext;
import org.m2acsi.entity.Action;
import org.m2acsi.entity.Demande;

/**
 *
 * @author Divi
 */
@DeclareRoles("ADMIN")
@Stateless
public class DemandeRessource {

    @PersistenceContext
    private EntityManager em;

    @Inject
    private Event<Demande> listener_d;

    @Inject
    private Event<Action> listener_a;

    //GET ID
    public Demande findById(long id) {
        return this.em.find(Demande.class, id);
    }

    //GET ALL
    public List<Demande> getAll() {
        return this.em.createNamedQuery("Demande.findAll", Demande.class).getResultList();
    }

    //GET STATUS
    public List<Demande> findByStatus(String statut) {
        return this.em.createQuery(
            "SELECT d FROM Demande d WHERE d.statut = ?1")
            .setParameter(1, statut)
            .getResultList();
    }

    //GET ALL ACTIONS
    public List<Action> getAllAction(Demande d) {
        return this.em.createNamedQuery("Actions.findAll", Action.class)
                .setParameter("demande_id", d.getId())
                .getResultList();
    }

    //DELETE
    public void delete(long id) {
        try {
            Demande d = this.em.getReference(Demande.class, id);
            this.em.remove(d);
        } catch (EntityNotFoundException e) {}
    }

    //POST Demande
    public Demande saveDemande(Demande d) {
        Demande dem = this.em.merge(d);
        listener_d.fire(dem);
        return dem;
    }

    //POST Action
    public Action saveAction(Action a) {
        Action act = this.em.merge(a);
        listener_a.fire(act);
        return act;
    }
}

DemandeRepresentation:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.m2acsi.boundary;

import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.m2acsi.entity.Action;
import org.m2acsi.entity.Demande;
import org.m2acsi.entity.TypeAction;

/**
 *
 * @author michel
 */
@Stateless
@Path("demandes")
@DeclareRoles("ADMIN")
public class DemandeRepresentation {

    @Inject
    private DemandeRessource ressource;

    @GET // GET id
    @Path("{id}")
    @Produces({MediaType.APPLICATION_JSON})
    public Response findById(@PathParam("id") long id) {
        Demande d = this.ressource.findById(id);
        if (d != null) {
            return Response.ok(d).build();
        } else {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    @PermitAll
    @RolesAllowed("ADMIN")
    public List<Demande> findByStatus(@QueryParam("statut") String statut) {
        if (statut == null) {
            return this.ressource.getAll(); //Si pas de ?statut on getAll
        } else {
            return this.ressource.findByStatus(statut); //Si statut on findByStatut       
        }
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON}) //Get demandes/{id}/actions
    @Path("{id}/actions")
    public List<Action> findAllActionsByDemande(@PathParam("id") long id) {
        Demande d = this.ressource.findById(id);
        return d.getActions();
    } 

    @GET
    @Produces({MediaType.APPLICATION_JSON}) //GET demandes/{id}/actions/{aid}
    @Path("{id}/actions/{aid}")
    public Action findActionById(@PathParam("id") long id, @PathParam("aid") int aid) {
        Demande d = this.ressource.findById(id);
        Action rep = null;
        for (Action a : d.getActions()) {
            if (a.getAid() == aid) {
                rep = a;
                break;
            }
        }
        return rep;
    }

    @POST //POST demandes
    public Response saveDemande(Demande d, @Context UriInfo uriInfo) {
        d.setStatut("Début");
        Action a = new Action(TypeAction.ATTENTE_ATTRIBUTION, "Michel", "en cours");
        d.addAction(a);
        Demande saved = this.ressource.saveDemande(d);
        long idd = saved.getId();
        URI uri = uriInfo.getAbsolutePathBuilder().path("/" + idd).build();
        return Response.created(uri).build();
    }

    @POST //POST demandes/{id}/actions
    @Path("{id}/actions")
    public Response saveAction(@PathParam("id") long id, Action a, @Context UriInfo uriInfo) {
        Demande d = this.ressource.findById(id);
        d.addAction(a);
        Action saved = a;
        SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy H:mm:ss");
        saved.setDate(formatter.format(new Date()));
        saved = this.ressource.saveAction(a);
        long idd = saved.getAid();
        URI uri = uriInfo.getAbsolutePathBuilder().path("/" + id +"actions/"+ idd).build();
        return Response.created(uri).build();
    }

    @PUT
    @Path("{id}")
    public Demande updateDemande(@PathParam("id") long id, Demande d) {
        d.setId(id);
        return this.ressource.saveDemande(d);
    }

    @PUT
    @Path("{id}/actions/{aid}")
    public Action updateAction(@PathParam("id") long id, @PathParam("aid") int aid, Action a) {
        a.setAid(aid);
        SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy H:mm:ss");
        a.setDate(formatter.format(new Date()));
        return this.ressource.saveAction(a);
    }

    @DELETE
    @Path("{id}")
    public void delete(@PathParam("id") long id) {
        this.ressource.delete(id);
    }


}

管理员:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.m2acsi.entity;

import java.io.Serializable;
import javax.annotation.security.DeclareRoles;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

/**
 *
 * @author michel
 */
@Entity
@Table(name = "ADMIN")
@NamedQuery(name="Admin.findAll", query="SELECT a FROM Admin a")
@DeclareRoles("ADMIN")
public class Admin implements Serializable{

    @Id
    @Column(name = "LOGIN")
    private String login;

    @Column(name = "MDP")
    private String mdp; //A crypter

    public Admin(){}

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getMdp() {
        return mdp;
    }

    public void setMdp(String mdp) {
        this.mdp = mdp;
    }

}

AdminRessource:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.m2acsi.boundary;

import java.util.List;
import javax.annotation.security.DeclareRoles;
import javax.ejb.Stateless;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceContext;
import org.m2acsi.entity.Action;
import org.m2acsi.entity.Admin;

/**
 *
 * @author Divi
 */
@DeclareRoles("ADMIN")
@Stateless
public class AdminRessource {

    @PersistenceContext
    private EntityManager em;

    @Inject
    private Event<Admin> listener;

    //GET ALL
    public List<Admin> getAll() {
        List<Admin> admins = this.em.createNamedQuery("Admin.findAll", Admin.class).getResultList();
        System.out.println(admins.get(0).getLogin());
        return admins;
    }
}
编辑:例外的StackTrace:

Avertissement:   StandardWrapperValve[org.m2acsi.passport.JAXRSConfiguration]: Servlet.service() for servlet org.m2acsi.passport.JAXRSConfiguration threw exception
java.lang.NullPointerException
    at org.m2acsi.util.AutentificatorFilter.isUserAllowed(AutentificatorFilter.java:78)
    at org.m2acsi.util.AutentificatorFilter.filter(AutentificatorFilter.java:69)
    at org.glassfish.jersey.server.ContainerFilteringStage.apply(ContainerFilteringStage.java:132)
    at org.glassfish.jersey.server.ContainerFilteringStage.apply(ContainerFilteringStage.java:68)
    at org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)
    at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:309)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:298)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
    at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:471)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:425)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:383)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:336)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:223)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:416)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:283)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:283)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:132)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:111)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:536)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
    at java.lang.Thread.run(Thread.java:745)

Infos:   keepstate options resolved to true, saving appId 95366951280836608 for application passport.
Infos:   /file:/C:/Users/michel/Documents/NetBeansProjects/passport/passport/target/passport/WEB-INF/classes/_org.m2acsi_passport_war_1.0PU logout successful
Grave:   One cannot have more than one of @RolesAllowed, @PermitAll, @DenyAll in the same AnnotatedElement.
 symbol: METHOD location: public java.util.List org.m2acsi.boundary.DemandeRepresentation.findByStatus(java.lang.String)

Grave:   One cannot have more than one of @RolesAllowed, @PermitAll, @DenyAll in the same AnnotatedElement.
 symbol: METHOD location: public java.util.List org.m2acsi.boundary.DemandeRepresentation.findByStatus(java.lang.String)

如果您有任何想法来解决它,请享受! 谢谢。

1 个答案:

答案 0 :(得分:0)

我找到了解决这个问题的方法。要询问我的数据库以了解哪些人可以访问我的资源,有必要在我的类AutentificatorFilter中的AdminRessource属性之前添加@EJB注释。